The Shared Pool在SGA中是SIZE较大的一个部分.有很多DBA没搞明白Shared Pool是用来做什么的,不知道怎么定Shared Pool的合适的SIZE.就随意的将它的SIZE搞得很大.有时候可能是不够大,但更多的时候是在浪费内存空间.而且太大的Shared Pool会影响性能.
块(Chunk):
要更好的理解Shared Pool,得对X$KSMSP表多做点研究.这个表中的每一个记录行对应的是Shared Pool内存中的一个Chunk(块).
SQL select ksmchcom, ksmchcls, ksmchsiz from x$ksmsp;
KSMCHCOM KSMCHCLS KSMCHSIZ
---------------- -------- ----------
KGL handles recr 496
PL/SQL MPCODE recr 1624
dictionary cach freeabl 4256
free memory free 1088
library cache freeabl 568
library cache recr 584
multiblock rea freeabl 2072
permanent memor perm 1677104
row cache lru recr 48
session param v freeabl 2936
sql area freeabl 2104
sql area recr 1208
上面的是对这个表查询的例子.(对整个表的查询有5726行左右的记录)
在每个Shared Pool Chunk已经分配好之后,代码将语句转化并使其有作用的这一过程实际上就称为一次分配.这个语句可以在X$KSMSP表中的KSMCHCOM字段看到,描述分配的内存Chunk.每一个Chunk都要比它所包含的对象要大,因为每个Chunk都有多出来16字节的头信息用于存储确认Chunk的类型、类别和大小SIZE还有用于Shared Pool管理的链接指针.
内存Chunk主要有四种类别,可以从X$KSMSP表中的KSMCHCLS看到.
free:这种类别的Chunk称为Free Chunk.它不包含有效的对象,可以自由分配.
recr:可重建的Chunk(Recreatable Chunk),这种Chunk有包含对象,而这些对象在必要的时候是可以临时被删除并在有需要的情况下进行重建.一个例子,包含Shared SQL Statements的Chunks就可以重建
freeabl:可释放的Chunk(Freeabl Chunk),这种Chunk也有包含对象,这些对象在一个session的生存期间是经常可用的而在session断掉之后就不可用.这些Chunks可以在session断开之前进行释放,可以部分释放也可以全部释放.Freeable Chunk是不能临时被删除的,因为它是不可重建的.
perm:永久性的内存Chunk(Permanent memory Chunk).它包含的对象是不能被释放的,是永久存在于内存中的.一些大的永久性的内存Chunk内部也包含一定量的free space.可以根据需要释放给shared poo.
select
ksmchcom contents,
count(*) chunks,
sum(decode(ksmchcls, 'recr', ksmchsiz)) recreatable,
sum(decode(ksmchcls, 'freeabl', ksmchsiz)) freeable,
sum(ksmchsiz) total
from
sys.x_$ksmsp
where
inst_id = userenv('Instance') and
ksmchcls not like 'R%'
group by
ksmchcom
KSMCHCOM CHUNKS RECR FREEABL TOTAL
---------------- ---------- ---------- ---------- ----------
KGFF heap 6 1296 2528 3824
KGK contexts 2 2400 2400
KGK heap 2 1136 1136
KGL handles 571 178616 178616
KQLS heap 404 87952 524888 612840
PL/SQL DIANA 274 42168 459504 501672
PL/SQL MPCODE 57 14560 88384 102944
PLS cca hp desc 1 168 168
PLS non-lib hp 1 2104 2104
character set m 5 23504 23504
dictionary cach 108 223872 223872
fixed allocatio 9 360 360
free memory 185 614088
kzull 1 48 48
library cache 1612 268312 356312 624624
multiblock rea 1 2072 2072
permanent memor 1 1677104
reserved stoppe 2 48
row cache lru 24 1168 1168
session param v 8 23488 23488
sql area 983 231080 1303792 1534872
table columns 19 18520 18520
table definiti 2 176 176
上面这个查询可以得到Shared Pool中所有Chunks的类型,类别和大小SIZE等相关信息.上面只列出部分记录.
Free Lists:
Shared Pool中的Free Chunks,于它们的大小为基准被组织成Free Lists或者Buckets.下面的一张表是Bucket号和Free Chunks SIZE的对应关系:
用下面这个脚本可以查询到Chunks数和每个Free List中的Free Space量.
select
decode(sign(ksmchsiz - 80), -1, 0, trunc(1/log(ksmchsiz - 15, 2)) - 5)
bucket,
sum(ksmchsiz) free_space,
count(*) free_chunks,
trunc(avg(ksmchsiz)) average_size,
max(ksmchsiz) biggest
from
sys.x_$ksmsp
where
inst_id = userenv('Instance') and
ksmchcls = 'free'
group by
decode(sign(ksmchsiz - 80), -1, 0, trunc(1/log(ksmchsiz - 15, 2)) - 5)
BUCKET FREE_SPACE FREE_CHUNKS AVERAGE_SIZE BIGGEST
---------- ---------- ----------- ------------ ----------
0 166344 3872 42 72
1 32208 374 86 96
4 928 1 928 928
6 11784 4 2946 3328
当一个进程需要Shared Pool Memory分配一个Chunk时,它首先会到Free Lists中查找与它所需的SIZE匹配的Chunk.如果跟所需的SIZE没有确切相符的Chunk可以分配则会继续在Free Lists中寻找一个更大的Chunk.如果找到的Chunk有24字节或者更多,则这个Chunk将会被分裂开来使用,将其余的Free Space部分返还到Free Lists中.如果上面的都找不到,则会从一个非空的Free Lists中找一个最小的Chunk给它使用.最后的方式是以LRU机制对Free Lists进行描述
Free Lists的描述,管理和Chunk的分配都是在Shared Pool Lathes的保护下进行的.如果Shared Pool包含有大量的小的Free Chunks时,在对这个特殊的Free Lists进行描述时,Shared Pool Lathes将会被占有比较长的一段时间.实际上,经常出现的Shared Pool Lathes的竞争和等待就是因为包含了大量的小的Free Chunks.所以增加Shared Pool 的SIZE并不能减少Shared Pool Lathes Contention而且还会使得这个竞争更加严重,这就是前面提到的将Shared Pool的SIZE设为很大并不一定会提高性能原因.
LRU Lists:
如果一个进程没办法从Shared Pool Free Lists中获得一个Free Chunk,则它会从Shared Pool中删除一个包含有Recreatable对象的Chunks来释放足够大的Chunks满足自己的使用.
Recreatable Chunks有两个种类:一种是Pinned在内存中的,一种是没有Pinned在内存中的.Pinned在内存中的Chunks跟用DBMS_SHARED_POOL.KEEP执行来KEEP在Shared Pool中是不一样的. DBMS_SHARED_POOL.KEEP是需要DBA来干预执行的,并且只能放在library cache中.而Pinned Chunks是自动执行的,它在Chunks包含正在使用的对象时就会自动被pinned在Shared Pool中.Pinned Recreatable Chunks是不能释放空间的,而Unpinned Recreatable Chunks是可以释放出来的.
在Shared Pool中,Unpinned Chunks被组织成两个Lists,它们都是以LRU机制来排列的.分别被称为临时的LRU List和循环的LRU List. Chunks在Unpinned时放在MRU(most recently used)的最后面,在它们pinned时将会从这个MRU List中删除.
在一个进程需要新分配一部分Shared Pool Memory内存时,Chunks也会从LRU List的最尾端删除.Chunks以每8个chunks为一个集而被flushed(暂时说为清空)-----首先是从临时的LRU List,然后再从循环的LRU List. Chunks是在不考虑SIZE的大小并且以LRU机制被flushed的.有一些Chunks是不能被 flushed的,如用DBMS_SHARED_POOL.KEEP执行后的包含library cache 对象的Chunks是不能被 flushed.这些Chunks通过pinned方式来代替被删除.
Unpinned Recreatable Chunks两种类型的LRU Lists: 临时的LRU List和循环的LRU List的长度可以从fixed表X$KGHLU查询到,还有已经flush掉的Chunks数,由于pinned和unpinned而加入到LRU List或者是从LRU List删除的Chunks数.从X$KGHLU表也可以知道LRU Lists被flushed完全但不成功(不理解)的次数和最近一次请求Chunk失败的所需要Chunk SIZE.具体看下面的语句:
column kghlurcr heading "RECURRENT|CHUNKS"
column kghlutrn heading "TRANSIENT|CHUNKS"
column kghlufsh heading "FLUSHED|CHUNKS"
column kghluops heading "PINS AND|RELEASES"
column kghlunfu heading "ORA-4031|ERRORS"
column kghlunfs heading "LAST ERROR|SIZE"
select
kghlurcr,
kghlutrn,
kghlufsh,
kghluops,
kghlunfu,