堆管理
shared pool是利用堆内存管理方式管理的(KGH:Kernel Generic Heap).从Oracle 9i开始,可以有多个最高级堆(TOP-LEVEL HEAP),最高级堆可以分为多个副堆,副堆下面还拥有下属副堆.堆和副堆的结构基本相同.从物理上来看,一个堆由于多个内存区以LINKED LIST的形式连接组成.一个内存区物理上使用一个GRANULE,一个内存区有多个CHUNK组成,所以CHUNK是HEAP的最小内存单位.CHUNK的使用情况可以通过X$KSMSP内部视图查看每个堆头上则包含了可使用的CHUNK列表和已使用的CHUNK列表.通过DUMP
HEAP命令可以在跟踪文件中观察HEAP和EXTENT的关系
alter session set events ‘immediate trace name heapdump level 2‘;
来看一下dump文件
[email protected]>select * from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
PL/SQL Release 11.2.0.1.0 - Production
CORE 11.2.0.1.0 Production
TNS for Linux: Version 11.2.0.1.0 - Production
NLSRTL Version 11.2.0.1.0 - Production
[email protected]>select * from v$sgainfo where name=‘Granule Size‘;
NAME BYTES RES
-------------------------------- ---------- ---
Granule Size 4194304 No
******************************************************
HEAP DUMP heap name="sga heap(1,0)" desc=0x2002b1cc
extent sz=0xfc4 alt=124 het=32767 rec=9 flg=-126 opc=0
parent=(nil) owner=(nil) nex=(nil) xsz=0x400000 heap=(nil)
fl2=0x20, nex=(nil)
latch set 1 of 1
durations enabled for this heap
reserved granules for root 27 (granule size 4194304)
EXTENT 0 addr=0x4d000000
Chunk 4d000038 sz= 24 R-freeable "reserved stoppe"
Chunk 4d000050 sz= 4193964 R-perm "perm " alo=4193964
Chunk 4d3ffefc sz= 236 R-free " "
Chunk 4d3fffe8 sz= 24 R-freeable "reserved stoppe"
EXTENT 1 addr=0x4e000000
Chunk 4e000038 sz= 24 R-freeable "reserved stoppe"
Chunk 4e000050 sz= 212888 R-free " "
Chunk 4e033fe8 sz= 24 R-freeable "reserved stoppe"
Chunk 4e034000 sz= 1544904 perm "perm " alo=1544904
Chunk 4e1ad2c8 sz= 2436408 perm "perm " alo=455948
EXTENT 2 addr=0x4e400000
Chunk 4e400038 sz= 24 R-freeable "reserved stoppe"
Chunk 4e400050 sz= 212888 R-free " "
Chunk 4e433fe8 sz= 24 R-freeable "reserved stoppe"
Chunk 4e434000 sz= 3973960 perm "perm " alo=3973960
Chunk 4e7fe348 sz= 3976 perm "perm " alo=3976
Chunk 4e7ff2d0 sz= 3376 free " "
EXTENT 3 addr=0x4e800000
Chunk 4e800038 sz= 24 R-freeable "reserved stoppe"
Chunk 4e800050 sz= 212888 R-free " "
Chunk 4e833fe8 sz= 24 R-freeable "reserved stoppe"
Chunk 4e834000 sz= 3953996 perm "perm " alo=3953996
Chunk 4ebf954c sz= 16400 perm "perm " alo=16400
Chunk 4ebfd55c sz= 7936 perm "perm " alo=7936
Chunk 4ebff45c sz= 2980 free " "
可以看出Oracle每次以EXTENT的形式为每个"sga heap"分配空间,而每个EXTENT的大小和GRANULE有关系
将EXTENT 0 中的所有Chunk相加:24+4193964+236+24=4194304-56
将EXTENT 1 中的所有Chunk相加:24+212888+24+1544904+2436408=4194304-56
将EXTENT 2 中的所有Chunk相加:24+212888+24+3953996+16400+7936+2980=4194304-56
这56到底是个啥?我没百度到,我猜是EXTENT HEADER的大小
Chunk
Chunk以链条Chain的形式存在于内存中,每个Chunk包含Header和Body两部分,Chunk的状态大体上分为:
FREE: 可马上使用
RECREATABLE: 可再生
FREEABLE: 只有在Session或Call期间内保存必要的对象状态
PERMANENT: 永久不可再生
其中FREE和RECREATABLE状态下的Chunk可重复使用
Free List
Free List主要用于管理空闲的Chunk,并且是用Bucket管理的.从Oracle 9i开始,一个堆总共有255个Bucket,Bucket所包含的Free Chunk大小随编号增加而递增,各Bucket下的Free Chunk以Linked list的形式连接
在DBA实战攻略一书中提到:同一个Bucket中的Chunk并不是按照大小排序的
同样在DBA思想天空中也有相似说明
那么实际是什么情况呢?
FREE LISTS:
Bucket 0 size=16
Bucket 1 size=20
Chunk 4e38e234 sz= 20 free " "
Chunk 4e34738c sz= 20 free " "
Bucket 2 size=24
Chunk 4e2a0ec4 sz= 24 free " "
Chunk 4d1e8e64 sz= 24 free " "
Chunk 4e147954 sz= 24 free " "
Chunk 4e33a93c sz= 24 free " "
Chunk 4e39b61c sz= 24 free " "
Bucket 3 size=28
Chunk 4e218efc sz= 28 free " "
Chunk 4e1af51c sz= 28 free " "
Chunk 4e17b9dc sz= 28 free " "
Chunk 4e1635e4 sz= 28 free " "
Chunk 4e1ff95c sz= 28 free " "
Chunk 4e1cac74 sz= 28 free " "
Chunk 4e294914 sz= 28 free " "
Bucket 4 size=32
Bucket 5 size=36
Bucket 6 size=40
Bucket 7 size=44
Bucket 8 size=48
Bucket 9 size=52
Bucket 10 size=56
Bucket 11 size=60
Bucket 12 size=64
Bucket 13 size=68
Chunk 4d202ad4 sz= 68 free " "
Chunk 4e12a47c sz= 68 free " "
Chunk 4e390234 sz= 68 free " "
Bucket 14 size=72
截取一段,我比较脑残,只能这么认为
如果真的不排序,那么当去Bucket循着链表找Chunk的时候,假如所需大小的Chunk刚好在链表的最后一位,就要遍历整条链表,这大大增加了持有Shared pool latch的时间
从我的DUMP可以看出,也许真的没有排序这一步,只不过由于BUCKET数量较8i大大增多,每个BUCKET中存在的Chunk多是一样大的?
真心希望知道的大神能给我解释解释
1.获得shared pool latch在free list中查找合适大小的空闲chunk。如果在获取shared pool latch时发生了争用,则会出现latch:shared pool等待事件。这时Oracle会一直持有shared pool latch,直到获得所需的内存为止。所在内存碎片化比较严重的shared pool中,进程持有shared pool latch的时间也会相应变长。
2.如果不存在合适大小的空闲chunk,则在查找到更大的空闲chunk后分割(split)使用,分割后剩下的内存区域则重新登记到free list中。分割内存意味着内存中的碎片开始增多。由于每个cursor所需内存的大小不同,所以shared pool的空闲内存不像buffer cache中的空闲内存一样具有固定大小.
3.如果检索了free list也没有找到所有合适的空闲chunk,则检索lru list。lru list上的chunk是重建(recreatable)的,而且是当前不使用的(没有处于pin状态).
4.如果在lru list上也没有找到合适的chunk,且所请求的内存还没有达到隐含参数_shared_pool_reserved_min_alloc的阈值,则追加分配share pool中剩余的内存空间.
5.如果以上请求的内存均失败,则出现ORA-4031错误
Shared pool的内存碎片化是不可避免的.为了减缓Shared Pool过度碎片化,如果释放的链各个内存片在物理上是相邻的,那么Oracle会将其合并成一个大内存片。也就是说Oracle会自动定期进行内存的碎片整理。
Lru List
Lru List主要保存着当前未使用而且可以重建的Chunk,当绘画在Free list中找不到空闲Chunk时,则会在Lru List中寻找
UNPINNED RECREATABLE CHUNKS (lru first):
Chunk 517a621c sz= 32 recreate "fixed allocatio" latch=0x2000fc90
Chunk 4ebbd94c sz= 332 recreate "KGLHD " latch=(nil)
Chunk 4eb9c7f8 sz= 332 recreate "KGLHD " latch=(nil)
Chunk 4eb66c68 sz= 332 recreate "KGLHD " latch=(nil)
Chunk 4eb6aaa4 sz= 332 recreate "KGLHD " latch=(nil)
Chunk 4eb3dadc sz= 332 recreate "KGLHD " latch=(nil)
Chunk 4eb3fde0 sz= 332 recreate "KGLHD " latch=(nil)
Chunk 4eb2e7fc sz= 332 recreate "KGLHD " latch=(nil)
Chunk 4efed6ec sz= 40 recreate "fixed allocatio" latch=0x4ff04cd8
Chunk 4eb283ec sz= 540 recreate "KQR PO " latch=0x4ff04cd8
Chunk 4eb28608 sz= 540 recreate "KQR PO " latch=0x4ff04cd8
Chunk 4eb27398 sz= 32 recreate "fixed allocatio" latch=0x4ff04920
Chunk 4eb2692c sz= 32 recreate "fixed allocatio" latch=0x2000e4cc
Chunk 4eb258f4 sz= 32 recreate "fixed allocatio" latch=0x4ff04570
Reserved Pool
Oracle是从7.1.5版本开始支持保留池的,保留池的设计目的是为了在共享池碎片化很严重的时候,还能够有一部分保留空间,用于较大的内存分配。
通过shared_pool_reserved_size来设置保留池大小,一般可以不设置,默认是5%
保留池使用条件
1.在共享池freelist中找不到足够大的Chunk
2.在lru list上也没有找不到合适的chunk或可重建的recreatable且状态为unpin的chunk
3.分配的内容要大于_SHARED_POOL_RESERVED_MIN_ALLOC(默认值为4400B),就是说超过这个值得内存分配才被认为是大内存分配
一些常用的系统对象往往在4000-4400B,因此在碎片化很严重且经常由于ORA-04031导致宕机的系统中,将这个参数设置得小一点(比如4000或3800)是十分有必要的
select indx from x$ksppi where upper(ksppinm) =‘_SHARED_POOL_RESERVED_MIN_ALLOC‘;
INDX
----------
153
[email protected]>select ksppstvl from x$ksppsv where indx =153;
KSPPSTVL
----------------------------------------------------------------------------------------------------
4400
select indx from x$ksppi where upper(ksppinm) =‘_SHARED_POOL_RESERVED_PCT‘;
INDX
----------
152
select ksppstvl from x$ksppsv where indx =152;
KSPPSTVL
----------------------------------------------------------------------------------------------------
5
保留池是否过小?
select REQUEST_MISSES from v$shared_pool_reserved;
这个查询,查询出在保留区申请不到空间的次数(request_failures),我们希望它是0,如果大于0,就要视情况考虑增大保留区大小
保留池是否过大?
reuest_misses为0且没有增长
Free space ≥ SHARED_POOL_RESERVED_SIZE Minimum
需要注意的是保留池会随着shared pool扩大而扩大,且即使缩小Shared Pool后也无法缩小,Flush也没用