暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

DBA手记:共享池的改进与ORA-04031的变化

原创 eygle 2011-02-18
785

我们知道,从Oracle 9i开始,Shared Pool可以被分割为多个子缓冲池(SubPool)进行管理,以提高并发性,减少竞争。


Shared Pool的每个SubPool可以被看作是一个Mini Shared Pool,拥有自己独立的Free List、内存结构以及LRU List。同时Oracle提供多个Latch对各个子缓冲池进行管理,从而避免单个Latch的竞争(Shared Pool Reserved Area同样进行分割管理)。SubPool最多可以有7个,Shared Pool Latch也从原来的一个增加到现在的7个。如果系统有4个或4个以上的CPU,并且SHARED_POOL_SIZE大于250MBOracle可以把Shared Pool分割为多个子缓冲池(SubPool)进行管理,在Oracle 9i中,每个SubPool至少为128MB


如果你看到过类似如下信息,那就意味着你可能遇到了SubPool的问题,如下所示:


Tue Dec 11 17:14:49 2007

Errors in file /oracle/app/admin/ctais2/udump/ctais2_ora_778732.trc:

ORA-04031: unable to allocate 4216 bytes of shared memory

("shared pool","IDX_DJ_NSRXX_P_NSRMCCTAIS2","sga heap(2,0)","library cache")

ORA-04031: unable to allocate 4216 bytes of shared memory

("shared pool","IDX_DJ_NSRXX_P_NSRMCCTAIS2","sga heap(2,0)","library cache")

Tue Dec 11 17:14:51 2007

Errors in file /oracle/app/admin/ctais2/bdump/ctais2_pmon_393248.trc:

ORA-04031: unable to allocate 4216 bytes of shared memory

("shared pool","unknown object","sga heap(2,0)","library cache")


Oracle 9i中多个子缓冲池的结构如图所示。

dbanb101.png


子缓冲池的数量受一个新引入的隐含参数_KGHDSIDX_COUNT影响。可以手工调整该参数(仅限于试验环境研究用),观察共享池管理的变化,可以通过如下步骤转储默认情况以及修改后的Shared Pool,再进行观察:


alter session set events
'immediate trace name heapdump level 2';


alter system set "_kghdsidx_count"=2
scope=spfile;


startup force;


alter session set events
'immediate trace name heapdump level 2';


以下是概要输出,注意在前者的跟踪文件中,sga heap(1,0)指共享池只存在一个子缓冲,后者则存在sga heap(1,0)以及sga heap(2,0)两个子缓冲池:


 [oracle@jumper udump]$ grep "sga heap"
eygle_ora_25766.trc


HEAP DUMP heap name="sga
heap"  desc=0x5000002c


HEAP DUMP heap name="sga heap(1,0)"  desc=0x5001ef0c


[oracle@jumper udump]$
grep "sga heap" eygle_ora_25786.trc


HEAP DUMP heap name="sga
heap"  desc=0x5000002c


HEAP DUMP heap name="sga heap(1,0)"  desc=0x5001ef0c


HEAP DUMP heap name="sga heap(2,0)"  desc=0x50023c04


子缓冲池的分配的算法很简单:


l  每个子缓冲池必须满足一定的内存约束条件;


l  4CPU可以分配一个子缓冲池,子缓冲池的数量最多7个。


Oracle 9i中,每个SubPool容量至少128MB,而在Oracle 10g中,每个子缓冲池至少为256MB。如前所述,SubPool的数量可以通过_kghdsidx_count参数来控制,但是没有参数可以显式地控制SubPool的大小。


根据以上规则,在一个12CPU的系统中,如果分配容量为300MBShared PoolOracle 9i将创建两个SubPool,每个容量大约150MB,如果共享池容量增加到500MBOracle将创建3SubPool,每个大约166MB


不管Oracle 9i中的128MB以及Oracle10g中的256MB,这样的SubPool在许多复杂的系统中,都可能是过小的,在这些情况下,可能要增大SubPool。可以通过控制Shared Pool大小以及SubPool的数量来改变SubPool的大小。一些Bug以及内部测试表明500MBSubPool可能会带来更好的性能,所以从Oracle 11g开始,每个SubPool至少为512MB


除大小控制之外,在Oracle
10g
中,Oracle仍然对共享池的管理做出了进一步改进,那就是对单个子缓冲池进行进一步的细分。现在默认,Oracle 10g会将单个缓冲池分割为4个子分区进行管理(这可能是因为通常4CPU才分配一个SubPool),使用类似如上的方法在Oracle 10gR2中进行测试:


alter session set events
'immediate trace name heapdump level 2';


alter system set "_kghdsidx_count"=2
scope=spfile;


startup force;


alter session set events
'immediate trace name heapdump level 2';


分析得到的日志,当仅有一个子缓冲池时,Shared Pool被划分为sga heap(1,0)sga heap(1,3)4个子分区:


 [oracle@eygle udump]$ grep "sga heap"
eygle_ora_13577.trc


HEAP DUMP heap name="sga
heap"  desc=0x2000002c


HEAP DUMP heap name="sga
heap(1,0)"  desc=0x2001b550


HEAP DUMP heap name="sga
heap(1,1)"  desc=0x2001c188


HEAP DUMP heap name="sga
heap(1,2)"  desc=0x2001cdc0


HEAP DUMP heap name="sga
heap(1,3)"  desc=0x2001d9f8


当使用两个子缓冲池时,Shared Pool则被划分为8个子分区进行管理如下:


 [oracle@eygle udump]$ grep "sga heap"
eygle_ora_13618.trc


HEAP DUMP heap name="sga
heap"  desc=0x2000002c


HEAP DUMP heap name="sga
heap(1,0)"  desc=0x2001b550


HEAP DUMP heap name="sga
heap(1,1)"  desc=0x2001c188


HEAP DUMP heap name="sga
heap(1,2)"  desc=0x2001cdc0


HEAP DUMP heap name="sga
heap(1,3)"  desc=0x2001d9f8


HEAP DUMP heap name="sga
heap(2,0)"  desc=0x20020640


HEAP DUMP heap name="sga
heap(2,1)"  desc=0x20021278


HEAP DUMP heap name="sga
heap(2,2)"  desc=0x20021eb0


HEAP DUMP heap name="sga
heap(2,3)"  desc=0x20022ae8


Oracle 10g中多缓冲池结构如图所示。

dbanb102.png


通过一个内部表X$KGHLU[K]ernel [G]eneric memory [H]eap manager State of [L]R[U] Of Unpinned
Recreatable chunks
)可以查询这些子缓冲池的分配:


SQL> select addr,indx,kghluidx,kghludur,kghluops,kghlurcr
from x$kghlu;


ADDR     INDX  
KGHLUIDX   KGHLUDUR   KGHLUOPS  
KGHLURCR


-------- ---- ----------
---------- ---------- ----------


B5F4C5B4    0         
2          3      12773        257


B5F4C1AC    1         
2          2      43675       1042


B5F4D9C8    2         
2          1      18831       1518


B5F4D5C0    3         
2          0          0          0


B5F4D1B8    4         
1          3     144697        327


B5F4E9E4    5          1          2    
483428       1462


B5F4E5DC    6          1          1       6558        982


B5F4E1D4    7          1          0          0          0


8 rows selected.


通过这一系列的算法改进OracleShared Pool管理得以不断增强较好地解决了大Shared Pool的性能问题Oracle 8i过大Shared Pool设置可能带来的栓锁争用等性能问题在某种程度上得以解决。从Oracle 10g开始,Oracle开始提供自动共享内存管理,使用该特性,用户可以不必显示设置共享内存参数,Oracle会自动进行分配和调整,虽然Oracle为用户提供了极大的便利,但是了解自动化后面的原理对于理解Oracle的运行机制仍然是十分重要的。


虽然多缓冲池技术使Oracle可以管理更大的共享池,但是SubPool的划分可能也会导致各分区之间的协调问题,甚至可能因为内存分散而出现ORA-04031错误。最常见的问题是某个子缓冲池(SubPool)可能出现过度使用,当新的进程仍然被分配到这个SubPool时,可能会导致内存请求失败(而此时其他SubPool可能还有很多内存空间)。


因为子缓冲池存在的种种问题,从Oracle 10g开始,允许内存请求在不同SubPool之间进行切换(Switch),从而提高了请求成功的可能(但是显然切换不可能是无限制的,所以问题仍然可能存在)。


 


以下是来自客户系统的一个实际案例,在一个Oracle9i的系统中,经常出现ORA-04031的错误,客户系统的主要配置如下:


SQL> select * from
v$version where rownum <2;


BANNER


----------------------------------------------------------------


Oracle9i Enterprise Edition
Release 9.2.0.6.0 - 64bit Production


SQL> show parameter
cpu_count


NAME                                 TYPE        VALUE


------------------------------------
----------- ------------------------------


cpu_count                            integer    
48


SQL> select * from
v$sga;


NAME                                      VALUE


------------------------------
----------------


Fixed Size                               762240


Variable Size                        2600468480


Database Buffers                    18975031296


Redo Buffers                            6578176


我们检查其参数设置,默认的子池设置是7个,代码如下:


SQL> select a.ksppinm,
b.ksppstvl from   x$ksppi a, x$ksppsv b


  2  where  a.indx = b.indx and a.ksppinm = '_kghdsidx_count';


KSPPINM                                                          KSPPSTVL


----------------------------------------------------------------
--------------------


_kghdsidx_count                                                 
7


7个子池都被使用,其Latch使用情况如下:


SQL> select child#,
gets from v$latch_children


  2  where
name = 'shared pool' order by child#;


    CHILD#      
GETS


---------- ----------


         1 
333403016


         2 
355720323


         3 
273944301


         4 
197980497


         5 
282347697


         6 
354398593


         7 
468809111


看一下具体的子池使用及内存情况,注意到各个Shared Pool子池平均分配了320MB内存左右,共享池合计约2256MB


SELECT      'shared pool (' || NVL (DECODE (TO_CHAR (ksmdsidx),
'0', '0 - Unused', ksmdsidx),'Total') || '):' subpool,


         SUM (ksmsslen) BYTES, ROUND (SUM (ksmsslen)
/ 1048576, 2) mb


    FROM x$ksmss WHERE ksmsslen > 0


GROUP BY ROLLUP (ksmdsidx)
ORDER BY subpool ASC


/


SUBPOOL                             BYTES         MB


------------------------------
---------- ----------


shared pool (1):                352321536        336


shared pool (2):                335544320        320


shared pool (3):                335544320        320


shared pool (4):                335544320        320


shared pool (5):                335544320        320


shared pool (6):                335544320        320


shared pool (7):                335544320        320


shared pool (Total):           2365587456       2256


 


8 rows selected.


进一步可以查询一下各个子池的剩余内存,注意到各个子池剩余内存约在7MB~15MB之间,而这些剩余内存又可能是零散的碎片:


SELECT   subpool, NAME, SUM (BYTES), ROUND (SUM (BYTES)
/ 1048576, 2) mb


    FROM (SELECT    'shared pool (' || DECODE (TO_CHAR (ksmdsidx),
'0', '0 - Unused', ksmdsidx)


                 || '):' subpool, ksmssnam NAME,
ksmsslen BYTES


            FROM x$ksmss WHERE ksmsslen > 0 AND
LOWER (ksmssnam) LIKE LOWER ('%free memory%'))


GROUP BY subpool, NAME
ORDER BY subpool ASC, SUM (BYTES) DESC


/


SUBPOOL                        NAME                           SUM(BYTES)         MB


------------------------------
------------------------------ ---------- ----------


shared pool (1):               free memory                       8158640       7.78


shared pool (2):               free memory                       7414472       7.07


shared pool (3):               free memory                       7831608       7.47


shared pool (4):               free memory                      10690992       10.2


shared pool (5):               free memory                      17201856       16.4


shared pool (6):               free memory                       8239920       7.86


shared pool (7):               free memory                      13925416      13.28


通过以下查询可以详细列举不同子池的Free内存块情况,从输出可以观察到,每个子池大于10KB的内存块都很少,这也就意味着,当有大块的共享内存请求时就可能出现ORA-04031错误(注意:R-free指保留池的剩余空间):


SQL> SELECT   ksmchidx "SubPool", 'sga heap(' ||
ksmchidx || ',0)' sga_heap,


  2      
    ksmchcom chunkcomment,


  3          
DECODE (ROUND (ksmchsiz / 1000),


  4                   0, '0-1K', 1, '1-2K',2, '2-3K',3,
'3-4K',4, '4-5K', 5, '5-6k',


  5                   6, '6-7k', 7, '7-8k',8, '8-9k',9,
'9-10k', '> 10K'


  6                  ) "size",


  7          
COUNT (*), ksmchcls status, SUM (ksmchsiz) BYTES


  8      FROM
x$ksmsp WHERE ksmchcom = 'free memory'


  9  GROUP
BY ksmchidx, ksmchcls, 'sga heap(' || ksmchidx || ',0)',ksmchcom, ksmchcls,


 10          
DECODE (ROUND (ksmchsiz / 1000),


 11                   0, '0-1K', 1, '1-2K',2, '2-3K',3,
'3-4K',4, '4-5K', 5, '5-6k',


 12                   6, '6-7k', 7, '7-8k',8, '8-9k',9,
'9-10k', '> 10K' );


SUBPOOL SGA_HEAP            CHUNKCOMMENT     size   
COUNT(*) STATUS        BYTES


------- -------------------
---------------- ----- ---------- -------- ----------


      1 sga heap(1,0)       free memory      0-1K        5173 free         922568


      1 sga heap(1,0)       free memory      1-2K        5422 free        5274920


.........


      1 sga heap(1,0)       free memory      6-7k           2 R-free        11968


      1 sga heap(1,0)       free memory      7-8k           9 R-free        62096


      1 sga heap(1,0)       free memory      8-9k          12 R-free        95480


      1 sga heap(1,0)       free memory      9-10k         11 R-free        99192


      1 sga heap(1,0)       free memory      > 10K         25 R-free       434272


      2 sga heap(2,0)       free memory      0-1K        4919 free         848864


.......


      2 sga heap(2,0)       free memory      9-10k          5 R-free        46056


      2 sga heap(2,0)       free memory      > 10K         43 R-free       769144


      3 sga heap(3,0)       free memory      0-1K        6921 free        1058264


。。。。。。


      3 sga heap(3,0)       free memory      9-10k          9 R-free        81344


      3 sga heap(3,0)       free memory      > 10K         64 R-free      1212424


      4 sga heap(4,0)       free memory      0-1K        6430 free         928688


.......


      4 sga heap(4,0)       free memory      9-10k          9 R-free        80464


      4 sga heap(4,0)       free memory      > 10K         34 R-free       689640


      5 sga heap(5,0)       free memory      0-1K        4416 free         779096


......


      5 sga heap(5,0)       free memory      9-10k          4 R-free        36344


      5 sga heap(5,0)       free memory      > 10K         40 R-free      1669384


      6 sga heap(6,0)       free memory      0-1K        6203 free         863104


。。。。。。


      6 sga heap(6,0)       free memory      9-10k  
      11 R-free        99464


      6 sga heap(6,0)       free memory      > 10K         56 R-free      1758912


      7 sga heap(7,0)       free memory      0-1K        3814 free         607616


......


      7 sga heap(7,0)       free memory      9-10k          6 R-free        54432


      7 sga heap(7,0)       free memory      > 10K         52 R-free      2816480


 


120 rows selected.


针对这种情况,我们可以相应减少Shared Pool子池的数量,以使得每个子池可以有足够的空闲内存可用。在这个客户环境中,首先将_kghdsidx_count调整为3ORA-04031错误即没有再次出现,调整之后,每个子池的内存扩大到750MB左右:


SUBPOOL                             BYTES         MB


------------------------------
---------- ----------


shared pool (1):                788529152        752


shared pool (2):                788529192        752


shared pool (3):                771751936        736


shared pool (Total):           2348810280       2240


 


现在每个子池的空闲内存达到了20MB~60MB左右:


SUBPOOL                        NAME                       SUM(BYTES)         MB


------------------------------
-------------------------- ---------- ----------


shared pool (1):               free memory                  56014080      53.42


shared pool (2):               free memory                  20292704      19.35


shared pool (3):               free memory                  67884912      64.74


调整后具体的内存使用情况如下,我们注意到,保留池的大块的空闲内存(R-free)数量大大增加,这样在要请求大块内存时,就更容易获得共享内存资源:


SUBPOOL SGA_HEAP         CHUNKCOMMENT     size   
COUNT(*) STATUS        BYTES


------- ----------------
---------------- ----- ---------- -------- ----------


     。。。。。。


      1 sga heap(1,0)    free memory      8-9k           6 free          48016


      1 sga heap(1,0)    free memory      > 10K          4 free          45448


  。。。。。。


      1 sga heap(1,0)    free memory      9-10k         22 R-free       197536


      1 sga heap(1,0)    free memory      > 10K  
     144 R-free      2606992


 。。。。。。


      2 sga heap(2,0)    free memory      9-10k          8 free          72784


      2 sga heap(2,0)    free memory      > 10K         15 free         172616


......


      2 sga heap(2,0)    free memory      9-10k         22 R-free       195280


      2 sga heap(2,0)    free memory      > 10K        155 R-free      2839248


。。。。。。


      3 sga heap(3,0)    free memory      8-9k          14 free         111736


      3 sga heap(3,0)    free memory      9-10k          1 free           8808


。。。。。。


      3 sga heap(3,0)    free memory      9-10k         29 R-free       261272


      3 sga heap(3,0)    free memory      > 10K        186 R-free      3434512


客户的系统是一个双节点RAC环境,在运行中,应用设置为只连接其中的一个节点,另外一个空闲节点的Shared
Pool
使用情况如下,列举供参考:


SUBPOOL SGA_HEAP        CHUNKCOMMENT     size   
COUNT(*) STATUS        BYTES


------- ---------------
---------------- ----- ---------- -------- ----------


      1 sga heap(1,0)   free memory      0-1K         373 free          41144


      1 sga heap(1,0)   free memory      1-2K           1 free           1488


      1 sga heap(1,0)   free memory      2-3K           1 free           1936


      1 sga heap(1,0)   free memory      3-4K           1 free           2704


      1 sga heap(1,0)   free memory      4-5K           1 free           3776


      1 sga heap(1,0)   free memory      9-10k          4 free          34864


      1 sga heap(1,0)   free memory      > 10K        157 free      460271664


      1 sga heap(1,0)   free memory      > 10K         38 R-free     25520800


      2 sga heap(2,0)   free memory      0-1K         357 free          37376


      2 sga heap(2,0)   free memory      3-4K           2 free           6152


      2 sga heap(2,0)   free memory      4-5K           1 free           3776


      2 sga heap(2,0)   free memory      > 10K        130 free      454592888


      2 sga heap(2,0)   free memory      > 10K         38 R-free     25520800


      3 sga heap(3,0)   free memory      0-1K         425 free          51280


      3 sga heap(3,0)   free memory      3-4K           1 free           2704


      3 sga heap(3,0)   free memory      7-8k           1 free           6664


      3 sga heap(3,0)   free memory      > 10K         44 free      467930312


      3 sga heap(3,0)   free memory      > 10K         38 R-free     25520800


ORA-04031出现时,可能共享池没有足够空闲内存,但是Shared Pool保留池(shared_pool_reserved_size)还有一定的内存空闲,所以我们可以释放降低使用保留池的内存大小,在这个案例中,降低_shared_pool_reserved_min_alloc参数设置,也帮助数据库更好地利用了保留内存。


最后修改时间:2022-06-07 17:51:34
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论