首页 > 代码库 > 理解Shared Pool 1

理解Shared Pool 1

技术分享
堆管理
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文件

sys@PROD>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

sys@PROD>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

sys@PROD>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也没用

理解Shared Pool 1