诊断并解决ORA-04031错误
当我们在共享池中试图分配大片的连续内存失败的时候,Oracle首先清除池中当前没使用的所有对象,使空闲内存块合并。如果仍然没有足够大单个的大块内存满足请求,就会产生ORA-04031错误。
当这个错误出现的时候你得到的错误解释信息类似如下:
1 [oracle@yft ~]$ oerr ora 04031 2 04031, 00000, "unable to allocate %s bytes of shared memory (\"%s\",\"%s\",\"%s\",\"%s\")" 3 // *Cause: More shared memory is needed than was allocated in the shared 4 // pool. 5 // *Action: If the shared pool is out of memory, either use the 6 // DBMS_SHARED_POOL package to pin large packages, 7 // reduce your use of shared memory, or increase the amount of 8 // available shared memory by increasing the value of the 9 // initialization parameters SHARED_POOL_RESERVED_SIZE and 10 // SHARED_POOL_SIZE. 11 // If the large pool is out of memory, increase the initialization 12 // parameter LARGE_POOL_SIZE.
1、共享池相关的实例参数
在继续之前,有必要理解下面的实例参数:
SHARED_POOL_SIZE
这个参数指定了共享池的大小,单位是字节。可以接受数字值或者数字后面跟上后缀"K"或"M"。"K"代表千字节,"M"代表兆字节。
SHARED_POOL_RESERVED_SIZE
指定了为共享池内存保留的用于大的连续请求的共享池空间。当共享池碎片强制使Oracle查找并释放大块未使用的池来满足当前的请求的时候,这个参数和SHARED_POOL_RESERVED_MIN_ALLOC参数一起可以用来避免性能下降。
这个参数理想的值应该大到足以满足任何对保留列表中内存的请求扫描而无需从共享池中刷新对象。既然操作系统内存可以限制共享池大小,一般来说,你应该设定这个参数为SHARED_POOL_SIZE参数的10%大小。
SHARED_POOL_RESERVED_MIN_ALLOC这个参数的值控制保留内存的分配。如果一个足够尺寸的大块内存在共享池空闲列表中没能找到,内存就从保留列表中分配一块比这个值大的空间。默认的值对于大多数系统来说都足够了。如果你加大这个值,那么Oracle服务器将允许从这个保留列表中更少的分配并且将从共享池列表中请求更多的内存。这个参数在Oracle 8i和更高的版本中是隐藏的。提交如下的语句查找这个参数值:
SQL> col name for a20; SQL> col value for a20; SQL> select nam.ksppinm name,val.ksppstvl value2 from x$ksppi nam,x$ksppsv val3 where nam.indx = val.indx and nam.ksppinm like '%shared%'4 order by 1;
10g注释:Oracle 10g的一个新特性叫做:"自动内存管理"允许DBA保留一个共享内存池来分shared pool,buffer cache,java pool和large pool。一般来说,当数据库需要分配一个大的对象到共享池中并且不能找到连续的可用空间,将自动使用其他SGA结构的空闲空间来增加共享池的大小。既然空间分配是Oracle自动管理的,ora-04031出错的可能性将大大降低。自动内存管理的初始化参数SGA_TARGET大于0的时候被激活。当前设定可以通过查询v$sga_dynamic_components视图获得。请参考10g管理手册以得到更多的内容。
2.诊断ORA-04031错误
注:大多数的常见的ORA-04031的产生和SHARED POOL SIZE有关,这篇文章中的诊断步骤大多都是关于共享池的。对于其它方面如large_pool或是java_pool,内存分配算法都是相似的,一般来说都是因为结构不够大造成。
ORA-04031可能是因为SHARED POOL不够大,或是因为碎片问题导致数据库不能找到足够大的内存块。
ORA-04031错误通常是因为库高速缓冲中或共享池保留空间中的碎片。在加大共享池大小的时候考虑调整应用,使用共享的SQL并且调整如下的参数:
SHARED_POOL_SIZE,
SHARED_POOL_RESERVED_SIZE,
SHARED_POOL_RESERVED_MIN_ALLOC.
首先判定是否ORA-04031错误是由共享池保留空间中的库高速缓冲的碎片产生的。提交下面的查询:
1 SQL> set linesize 200; 2 SQL> select free_space,avg_free_size,used_space,avg_used_size,request_failures, 3 2 last_failure_size 4 3 from v$shared_pool_reserved; 5 6 FREE_SPACE AVG_FREE_SIZE USED_SPACE AVG_USED_SIZE REQUEST_FAILURES LAST_FAILURE_SIZE 7 ---------- ------------- ---------- ------------- ---------------- ----------------- 8 4700660 167880.714 16333900 583353.571 0
如果:
REQUEST_FIIURES > 0 并且LAST_FAILURE_SIZE > SHARED_POOL_RESERVED_MIN_ALLOC
那么ORA-04031错误就是因为共享池保留空间缺少连续空间所致。要解决这个问题,可以考虑加大SHARED_POOL_RESERVED_MIN_ALLOC来降低缓冲进共享池保留空间的对象数目,并增加SHARED_POOL_RESERVED_SIZE和SHARED_POOL_SIZE来加大共享池保留空间的可用内存。
如果:
REQUEST_FAILURES > 0 并且 LAST_FAILURE_SIZE < SHARED_POOL_RESERVED_MIN_ALLOC
或者
REQUEST_FAILURES 等于0 并且 LAST_FAILURE_SIZE < SHARED_POOL_RESERVED_MIN_ALLOC
那么是因为在库高速缓冲缺少连续空间导致ORA-04031错误。
第一步应该考虑降低SHARED_POOL_RESERVED_MIN_ALLOC以放入更多的对象到共享池,保留空间中并且加大SHARED_POOL_SIZE。
3.解决ORA-04031错误
ORACLE BUG
Oracle推荐对你的系统打上最新的PatchSet。大多数的ORA-04031错误都和BUG相关,可以通过使用这些补丁来避免。
下面表中总结和这个错误相关的最常见的BUG、可能的环境和修补这个问题的补丁。
编译Java代码时出现的ORA-04031
在你编译Java代码的时候如果内存溢出,你会看到错误:
1 A SQL exception occurred while compiling: 2 ORA-04031: unable to allocate bytes of shared memory 3 ("shared pool","unknown object","joxlod: init h","JOX: ioc_allocate_pal")
解决办法是关闭数据库然后把参数JAVA_POOL_SIZE设定为一个较大的值。这里错误信息中提到的"shared pool"其实共享全局区(SGA)溢出的误导,并不表示你需要增加SHARED_POOL_SIZE,相反,你必须加大JAVA_POOL_SIZE参数的值,然后重启系统,再试一下。参考:<Bug:2736601>。
小的共享池尺寸
很多情况下,共享池过小能够导致ORA-04031错误。下面信息有助于你调整共享池大小:
库高速缓冲命中率
命中率有助于你衡量共享池的使用,有多少语句需要被解析而不是重用。下面的SQL语句有助于你计算库高速缓冲的命中率:
1 SQL> select sum(pins) "executions", 2 2 sum(reloads) "cache misses while executing" 3 3 from v$librarycache; 4 5 executions cache misses while executing 6 ---------- ---------------------------- 7 29634 131
如果丢失超过1%,那么尝试通过加大共享池的大小来减少库高速缓冲丢失。
共享池大小计算
要计算最合适你工作负载的共享池大小,请参考:
<Note:1012046.6>:HOW TO CALCULATE YOUR SHARED POOL SIZE.
共享池碎片
每一次,需要被执行的SQL或者PL/SQL语句的解析形式载入共享池中都需要一块特定的连续的空间。数据库要扫描的第一个资源就是共享池中的空闲可用内存。一旦空闲内存耗尽,数据库要查找一块已经分配但还没使用的内存准备重用。如果这样的确切尺寸的大块内存不可用,就继续按照如下标准寻找:
大块(chunk)大小比请求的大小大;
空间是连续的;
大块内存是可用的(而不是正在使用的)。
这样大块的内存被分开,剩余的添加到相应的空闲空间列表中。当数据库以这种方式操作一段时间之后,共享池结构就会出现碎片。
当共享池存在碎片的问题,分配一片空闲的空间就会花费更多的时间,数据库性能也会下降(整个操作的过程中,"chunk allocation"被一个叫做"shared pool latch"的闩所控制)或者是出现ORA-04031错误errors(在数据库不能找到一个连续的空闲内存块的时候)。
参考<Note:616223.1>:可以得到关于共享池碎片的详细讨论。
如果SHARED_POOL_SIZE足够大,大多数的ORA-04031错误都是由共享池中的动态SQL碎片导致的。可能的原因如下:
非共享的SQL;
生产不必要的解析调用(软解析);
没有使用绑定变量
要减少碎片的产生你需要确定是前面描叙的几种可能的因素。可以采取如下的一些方法,当然不只局限于这几种:应用调整、数据库调整或者实例参数调整。
请参考<Note:62143.1>,描述了所有的这些细节内容。这个注释还包括了共享池如何工作的细节。
下面的视图有助于你标明共享池中非共享的SQL/PLSQL:
V$SQLAREA视图
这个视图保存了在数据库中执行的SQL语句和PL/SQL块的信息。下面的SQL语句可以显示给你带有literal的语句或者是带有绑定变量的语句:
1 SQL> col sql_text for a45; 2 SQL> select substr (sql_text,1,40) "SQL",count(*), 3 2 sum (executions) "TotExecs" 4 3 from v$sqlarea 5 4 where executions < 5 6 5 group by substr (sql_text,1,40) 7 6 having count(*) > 30 8 7 order by 2;
注:Having后的数值"30"可以根据需要调整以得到更为详细的信息。
X$KSMLRU视图
这个固定表x$ksmlru跟踪共享池中导致其它对象换出(age out)的应用。这个固定表可以用来标记是什么导致了大的应用。
如果很多对象在共享池中都被阶段性的刷新可能导致响应时间问题并且有可能在对象重载入共享池中的时候导致库高速缓冲闩竞争问题。
关于这个x$ksmlru表的一个不寻常的地方就是如果有人从表中选取内容这个表的内容就会被擦除。这样这个固定表只存储曾经发生的最大的分配。这个值在选择后被重新设定这样接下来的大的分配可以被标记,即使它们不如先前的分配过的大。因为这样的重置,在查询提交后的结果不可以再次得到,从表中的输出的结果应该小心的保存。监视这个固定表运行如下操作:
1 SQL> select * from x$ksmlru where ksmlrsiz > 0;
这个表只可以用SYS用户登录进行查询。
X$KSMSP视图(类似堆Heapdump信息)
使用这个视图能找出当前分配的空闲空间,有助于理解共享池碎片的程度。如我们在前面的描述,查找为游标分配的足够的大块内存的第一个地方是空闲列表(free list)。下面的语句显示了空闲列表中的大块内存:
SQL> SELECT '0 (<140)' bucket, ksmchcls, 10 * TRUNC (ksmchsiz / 10) "From",COUNT (*) "Count", MAX (ksmchsiz) "Biggest",TRUNC (AVG (ksmchsiz)) "AvgSize", TRUNC (SUM (ksmchsiz)) "Total"FROM x$ksmspWHERE ksmchsiz < 140 AND ksmchcls = 'free' GROUP BY ksmchcls, 10 * TRUNC (ksmchsiz / 10) UNION ALL SELECT '1 (140-267)' bucket, ksmchcls, 20 * TRUNC (ksmchsiz / 20),COUNT (*), MAX (ksmchsiz), TRUNC (AVG (ksmchsiz)) "AvgSize",TRUNC (SUM (ksmchsiz)) "Total"FROM x$ksmspWHERE ksmchsiz BETWEEN 140 AND 267 AND ksmchcls = 'free' GROUP BY ksmchcls, 20 * TRUNC (ksmchsiz / 20) UNION ALL SELECT '2 (268-523)' bucket, ksmchcls, 50 * TRUNC (ksmchsiz / 50),COUNT (*), MAX (ksmchsiz), TRUNC (AVG (ksmchsiz)) "AvgSize",TRUNC (SUM (ksmchsiz)) "Total"FROM x$ksmspWHERE ksmchsiz BETWEEN 268 AND 523 AND ksmchcls = 'free' GROUP BY ksmchcls, 50 * TRUNC (ksmchsiz / 50) UNION ALL SELECT '3-5 (524-4107)' bucket, ksmchcls, 500 * TRUNC (ksmchsiz / 500),COUNT (*), MAX (ksmchsiz), TRUNC (AVG (ksmchsiz)) "AvgSize",TRUNC (SUM (ksmchsiz)) "Total"FROM x$ksmspWHERE ksmchsiz BETWEEN 524 AND 4107 AND ksmchcls = 'free' GROUP BY ksmchcls, 500 * TRUNC (ksmchsiz / 500) UNION ALL SELECT '6+ (4108+)' bucket, ksmchcls, 1000 * TRUNC (ksmchsiz / 1000),COUNT (*), MAX (ksmchsiz), TRUNC (AVG (ksmchsiz)) "AvgSize",TRUNC (SUM (ksmchsiz)) "Total"FROM x$ksmspWHERE ksmchsiz >= 4108 AND ksmchcls = 'free'GROUP BY ksmchcls, 1000 * TRUNC (ksmchsiz / 1000);BUCKET KSMCHCLS From Count Biggest AvgSize Total -------------- -------- ---------- ---------- ---------- ---------- ---------- 0 (<140) free 20 36 28 24 884 0 (<140) free 70 10 76 73 736 0 (<140) free 40 13 48 46 604 0 (<140) free 100 2 108 106 212 0 (<140) free 80 20 88 85 1708 0 (<140) free 50 15 56 52 792 0 (<140) free 30 22 36 34 764 0 (<140) free 120 7 120 120 840 0 (<140) free 60 11 68 63 696 1 (140-267) free 240 1 248 248 248 1 (140-267) free 220 1 228 228 228BUCKET KSMCHCLS From Count Biggest AvgSize Total -------------- -------- ---------- ---------- ---------- ---------- ---------- 1 (140-267) free 200 2 208 206 412 1 (140-267) free 140 1 156 156 156 2 (268-523) free 400 1 416 416 416 2 (268-523) free 450 2 476 476 952 3-5 (524-4107) free 1000 2 1424 1224 2448 3-5 (524-4107) free 500 2 880 712 1424 3-5 (524-4107) free 1500 1 1532 1532 1532 6+ (4108+) free 1646000 1 1646592 1646592 1646592 6+ (4108+) free 9000 1 9432 9432 9432 6+ (4108+) free 1915000 1 1915828 1915828 1915828 6+ (4108+) free 3891000 1 3891140 3891140 389114022 rows selected.
4.ORA-04031错误与Large Pool
大池是个可选的内存区,为以下的操作提供大内存分配:
MTS会话内存和Oracle XA接口;
Oracle备份与恢复操作和I/O服务器进行用的内存(缓冲);
并行执行消息缓冲。
大池没有LRU列表。这和共享池中的保留空间不同,保留空间和共享池中其他分配的内存使用同样的LRU列表。大块内存从不会换出大池中,内存必须是显式的被每个会话分配并释放。一个请求如果没有足够的内存,就会产生类似这样的一个ORA-04031错误:
1 ORA-04031:unable to allocate XXXX bytes of shared memory 2 ("large pool","unknown object","session heap","frame")
这个错误发生时候可以检查几件事情:
1).使用如下语句检查v$sgastat,得知使用和空闲的内存:
1 SQL> select pool,name,bytes from v$sgastat where pool = 'large pool'; 2 3 POOL NAME BYTES 4 ------------ -------------------------- ---------- 5 large pool PX msg pool 491520 6 large pool free memory 3702784
2).你还可以采用heapdump level 32来dump大池的堆并检查空闲的大块内存的大小
从大池分配的内存如果是LARGE_POOL_MIN_ALLOC子节的整块数有助于避免碎片。任何请求分配小于LARGE_POOL_MIN_ALLOC大块尺寸都将分配LARGE_POOL_MIN_ALLOC的大小。一般来说,你会看到使用大池的时候相对共享池来说要用到更多的内存。通常要解决大池中的ORA-04031错误必须增加LARGE_POOL_SIZE的大小。
5.ORA-04031和共享池刷新
有一些技巧提高游标的共享能力,从而共享池碎片和ORA-04031都会减少。最佳途径是调整应用使用绑定变量。另外在应用不能调整的时候考虑使用CURSOR_SHARING参数和FORCE不同的值来做到(要注意那会导致执行计划改变,所以建议先对应用进行测试)。当上述技巧都不可以用的时候,并且碎片问题在系统中比较严重,刷新共享池可能有助于减轻碎片问题。但是,必须加以如下考虑:
刷新将导致所有没有被使用的游标从共享池删除。这样,在共享池刷新之后,大多数SQL和PL/SQL游标必须被硬解析。这将提供CPU的使用,也会加大Latch的活动。
当应用程序没有使用绑定变量并被需要用户进行类似的操作的时候(如在OLTP系统中),刷新之后会很快还会出现碎片问题。所以共享池对设计糟糕的应用程序来说不是解决办法。
对一个大的共享池刷新可能会导致系统挂起,尤其是实例繁忙的时候,推荐的非高峰的时候刷新
6.ORA-04031错误的高级分析
如果前述的这些技术内容都不能解决ORA-04031错误,可能需要额外的跟踪信息来得到问题发生的共享池的快照。
调整init.ora参数添加如下的事件得到该问题的跟踪信息:
event = "4031 trace name errorstack level 3"
event = "4031 trace name HEAPDUMP level 3"
如果问题可重现,该事件可设定在会话层,在执行问题语句之前使用如下的语句:
SQL>alter session set events '4031 trace name errorstack level 3';
SQL>alter session set events '4031 trace name HEAPDUMP level 3';
把这个跟踪文件发给Oracle支持人员进行排错。