随着会话不停地从SHARED POOL中分配内存,SHARED POOL中完整连续的内存区域可能会越来越小,这时如果会话需要分配大内存,可能会分配失败。为了减小出现该类型错误的概率,Oracle设置了保留内存区域,该区域用RESERVED FREE LIST管理。其大小由参数SHARED_POOL_RESERVED_SIZE决定(最小为5000字节,最大不能超过SHARED POOL大小的一半)。RESERVED FREE LIST在最高级堆中出现,可以通过DUMP HEAP观察RESERVED FREE LIST:
RESERVED FREE LISTS:
Reserved bucket 0 size=16
Reserved bucket 1 size=4400
Reserved bucket 2 size=8204
Reserved bucket 3 size=8460
Reserved bucket 4 size=8464
Reserved bucket 5 size=8468
Reserved bucket 6 size=8472
Reserved bucket 7 size=9296
Reserved bucket 8 size=9300
Reserved bucket 9 size=12320
Reserved bucket 10 size=12324
Reserved bucket 11 size=16396
Reserved bucket 12 size=32780
Reserved bucket 13 size=65548
Chunk 67000050 sz= 839576 R-free " "
Chunk 68000050 sz= 839576 R-free " "
Chunk 69000050 sz= 839576 R-free " "
Chunk 6b00007c sz= 839532 R-free " "
Reserved bucket 14 size=7968764
Total reserved free space = 3358260
Oracle对进入RESERVED FREE LIST的对象有大小限制,即只有大于_shared_pool_reserved_min_alloc隐含参数阀值(默认值为4400)的CURSOR才能进入RESERVED FREE LIST。所以有可能出现SHARED POOL有大量空闲空间但进程却无法分配到所需内存的情况,如下所示:
Tue Aug 8 10:52:48 2008
Errors in file /oracle/admin/zhjs/bdump/zhjs2_j000_10084.trc:
ORA-00604: error occurred at recursive SQL level 1
ORA-04031: unable to allocate 4116 bytes of shared memory ("shared pool","JOB$SYS","KGLS heap","KGLS MEM BLOCK"
)
产生这种现象主要有以下2个原因:
SHARED POOL内存碎片化严重,进程无法获得所需大小的内存。即FREE LIST和LRU LIST内存碎片化严重。
所需内存大小没有达到从RESERVED FREE LIST中分配内存的阀值。
通过查询视图V$SHARED_POOL_RESERVED可以观察RESERVED FREE LIST的状态,如下所示:
SQL> select FREE_SPACE,AVG_FREE_SIZE,USED_SPACE,REQUEST_FAILURES,LAST_FAILURE_SIZE
2 from V$SHARED_POOL_RESERVED;
FREE_SPACE AVG_FREE_SIZE USED_SPACE REQUEST_FAILURES LAST_FAILURE_SIZE
---------- ------------- ---------- ---------------- -----------------
663913712 155958.119 27944704 2110 4192
可以看到系统共出现过2110次内存分配失败,最近一次分配的内存大小是4192字节,为了减少内存分配失败次数,可以调整_shared_pool_reserved_min_alloc隐含参数至4100字节。需要注意的是,由于存在BUG 3669074,在Oracle 10.2之前查询视图V$SHARED_POOL_RESERVED可能会导致错误结果,可以使用以下脚本观察RESERVED FREE LIST:
select p.inst_id, p.free_space, p.avg_free_size, p.free_count,
p.max_free_size, p.used_space, p.avg_used_size, p.used_count, p.max_used_size,
s.requests, s.request_misses, s.last_miss_size, s.max_miss_size,
s.request_failures, s.last_failure_size, s.aborted_request_threshold,
s.aborted_requests, s.last_aborted_size
from (select avg(x$ksmspr.inst_id) inst_id,
sum(decode(ksmchcls,'R-free',ksmchsiz,0)) free_space,
avg(decode(ksmchcls,'R-free',ksmchsiz,0)) avg_free_size,
sum(decode(ksmchcls,'R-free',1,0)) free_count,
max(decode(ksmchcls,'R-free',ksmchsiz,0)) max_free_size,
sum(decode(ksmchcls,'R-free',0,ksmchsiz)) used_space,
avg(decode(ksmchcls,'R-free',0,ksmchsiz)) avg_used_size,
sum(decode(ksmchcls,'R-free',0,1)) used_count,
max(decode(ksmchcls,'R-free',0,ksmchsiz)) max_used_size from x$ksmspr
where ksmchcom not like '%reserved sto%') p,
(select sum(kghlurcn) requests, sum(kghlurmi) request_misses,
max(kghlurmz) last_miss_size, max(kghlurmx) max_miss_size,
sum(kghlunfu) request_failures, max(kghlunfs) last_failure_size,
max(kghlumxa) aborted_request_threshold, sum(kghlumer) aborted_requests,
max(kghlumes) last_aborted_size from x$kghlu) s;
由于硬解析时需要从SHARED POOL中分配内存(分配内存时需要持有SHARED POOL LATCH),所以在硬解析(HARD PARSE)比较多的系统中,非常容易引起SHARED POOL LATCH的争用。为了减缓该LATCH的争用,从Oracle 9i开始,共享池可分为多个子池来管理(最多7个),下一节将主要讲解SHARED POOL的SUB POOL技术。