10g引入ASMM后SGA_TARGET取代shared_pool_size,db_cache_size等参数,成为DBA关注的主要SGA内存管理参数;有不少情况下SGA_TARGET参数会设置为一个小于SGA_MAX_SIZE的值(这样做在多实例情况下更具灵活性)。但不少人会问,这样岂不是要浪费一部分物理内存吗?Oracle会为实例分配SGA_MAX_SIZE大小的内存的,SGA_TARGET要设得和SGA_MAX_SIZE一样大才合理啊!
让我们来看看实际的情况:
SQL> select * from v$version;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bi
PL/SQL Release 10.2.0.4.0 - Production
CORE 10.2.0.4.0 Production
TNS for Linux: Version 10.2.0.4.0 - Production
NLSRTL Version 10.2.0.4.0 - Production
/* linux上的10.2.0.4 */
SQL> show parameter sga
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
lock_sga boolean FALSE
pre_page_sga boolean FALSE
sga_max_size big integer 3600M
sga_target big integer 368M
SQL> col component for a25;
SQL> select component, current_size / 1024 / 1024, last_oper_type
2 from v$sga_dynamic_components
3 where current_size != 0;
COMPONENT CURRENT_SIZE/1024/1024 LAST_OPER_TYP
------------------------- ---------------------- -------------
shared pool 96 STATIC
large pool 16 STATIC
java pool 16 STATIC
DEFAULT buffer cache 224 INITIALIZING
/* 此时的SGA_TARGET为368M,而SGA_MAX_SIZE为3600M */
/* 我们来看一下实际的物理内存使用情况 */
/* 以root用户登录,因为我们需要用到清理文件系统缓存的命令 */
[maclean@rh2 ~]$ su - root
Password:
[root@rh2 ~]# sync
[root@rh2 ~]# sync
/* sync 命令用以写出文件系统脏缓存,类似于Oracle的checkpoint手动检查点 */
[root@rh2 ~]# echo 3 > /proc/sys/vm/drop_caches
[root@rh2 ~]# echo 3 > /proc/sys/vm/drop_caches
/* 将proc文件系统下的drop_caches文件置为3,清理文件系统缓存,以免其干扰我们的实验 */
[root@rh2 ~]# free
total used free shared buffers cached
Mem: 4046352 429328 3617024 0 296 176100
-/+ buffers/cache: 252932 3793420
Swap: 10241428 0 10241428
/* 4g内存中仅有419M处于使用状态,其他均为free。可见Oracle没有为实例分配大小等于SGA_MAX_SIZE的内存空间,而接近于SGA_TARGET_SIZE的大小 */
[root@rh2 ~]# ps -ef|grep pmon|grep -v grep
maclean 6361 1 0 18:35 ? 00:00:00 ora_pmon_YOUYUS
[root@rh2 ~]# pmap -x 6361
6361: ora_pmon_YOUYUS
Address Kbytes RSS Dirty Mode Mapping
0000000000400000 100412 7300 0 r-x-- oracle
000000000680f000 544 180 64 rwx-- oracle
0000000006897000 148 104 104 rwx-- [ anon ]
000000001e9d0000 672 532 532 rwx-- [ anon ]
0000000060000000 3688448 1044 388 rwxs- [ shmid=0x390005 ]
/* 利用pmap工具探测Oracle后台进程的内存地址空间,可以看到这里虚拟共享内存段(也就是SGA)的大小为3602M */
[root@rh2 ~]# ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x74018366 3112960 root 600 4 0
0x00000000 3473409 root 644 80 2
0x74018365 3080194 root 600 4 0
0x00000000 3506179 root 644 16384 2
0x00000000 3538948 root 644 280 2
0x1cdd16e8 3735557 maclean 640 3776970752 15
/* 使用ipcs 命令也可以观察到这个大小为3602M的共享内存段 */
/* 可以猜测Oracle在这里使用malloc函数或类似的方法实现虚拟内存的分配,没有像calloc函数那样对空间中的每一位都初始为0,保证了不浪费物理内存 */
/* 我们动态修改SGA_TARGET参数来看看* /
SQL> alter system set sga_target=3000M;
System altered.
SQL> select component, current_size / 1024 / 1024, last_oper_type
2 from v$sga_dynamic_components
3 where current_size != 0;
COMPONENT CURRENT_SIZE/1024/1024 LAST_OPER_TYP
------------------------- ---------------------- -------------
shared pool 96 STATIC
large pool 16 STATIC
java pool 16 STATIC
DEFAULT buffer cache 2864 INITIALIZING
/* BUFFER_CACHE 的空间大幅增加 * /
SQL> !free
total used free shared buffers cached
Mem: 4046352 3187784 858568 0 536 2889920
-/+ buffers/cache: 297328 3749024
Swap: 10241428 0 10241428
/* used mem部分上升到3113M,随着SGA_TARGET的动态增长而增长了 */
/* 如果我们改小SGA_TARGET呢? */
SQL> alter system set sga_target=368M;
System altered.
SQL> select component, current_size / 1024 / 1024, last_oper_type
2 from v$sga_dynamic_components
3 where current_size != 0;
COMPONENT CURRENT_SIZE/1024/1024 LAST_OPER_TYP
------------------------- ---------------------- -------------
shared pool 96 STATIC
large pool 16 STATIC
java pool 16 STATIC
DEFAULT buffer cache 224 SHRINK
/* 可以看到BUFFER CACHE最近执行了SHRINK收缩操作,SIZE下降到224M */
QL> !free
total used free shared buffers cached
Mem: 4046352 3204608 841744 0 1596 2912888
-/+ buffers/cache: 290124 3756228
Swap: 10241428 0 10241428
/* 此时OS层仍认为used memory部分为3130M;但可以放心,它们是可被其他进程复用的 * /
官方对pre_page_sga参数的定义是"PRE_PAGE_SGA determines whether Oracle reads the entire SGA into memory at instance startup. Operating system page table entries are then prebuilt for each page of the SGA. This setting can increase the amount of time necessary for instance startup, but it is likely to decrease the amount of time necessary for Oracle to reach its full performance capacity after startup." 它决定Oracle是否在启动阶段将整个SGA读入内存,实际上在启动阶段SGA的内容是十分稀疏的,当pre_page_sga为TRUE时Oracle所要做的是向OS所要SGA_MAX_SIZE大小的实际物理页。
我们来看一下这个参数的实际效果:
SQL> alter system set sga_max_size=2500M scope=spfile;
System altered.
SQL> alter system set pre_page_sga=true scope=spfile;
System altered.
SQL> startup force ;
ORACLE instance started.
Total System Global Area 2634022912 bytes
Fixed Size 2086288 bytes
Variable Size 2382367344 bytes
Database Buffers 234881024 bytes
Redo Buffers 14688256 bytes
Database mounted.
Database opened.
[root@rh2 ~]# echo 3 > /proc/sys/vm/drop_caches
SQL> show parameter sga
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
lock_sga boolean FALSE
pre_page_sga boolean TRUE
sga_max_size big integer 2512M
sga_target big integer 368M
SQL> !free
total used free shared buffers cached
Mem: 4046352 2895256 1151096 0 648 2623692
-/+ buffers/cache: 270916 3775436
Swap: 10241428 104936 10136492
/* 设置pre_page_sga参数为true后,Oracle实际分配的物理内存不再局限于SGA_TARGET,而是在实例生命周期内几乎恒等于SGA_MAX_SIZE指定的值了 * /
/* 当SGA_TARGET配合pre_page_sga使用时,这的确可能造成一种浪费 ! * /
10g中Oracle已经强烈不建议使用pre_page_sga参数了,在ASMM下它带来的问题可不小!