Oracle ORA-4031解决思路

来源:这里教程网 时间:2026-03-03 18:12:42 作者:

诊断并解决  ORA-04031  错误      对于大多数应用来说,共享池的大小对于  Oracle  性能来说都是很重要的。共享池中保存数据字典高速缓冲和完全解析或编译的的  PL/SQL  块和  SQL  语句。

当我们在共享池中试图分配大片的连续内存失败的时候,  Oracle  首先刷新池中当前没使用的所有对象  ,  使空闲内存块合并。如果仍然没有足够大单个的大块内存满足请求  ,  就会产生  ORA-04031  错误。 当这个错误出现的时候你得到的错误信息如下  :

Error: ORA 4031   Text: unable to allocate %s bytes of shared memory (%s,%s,%s)   ----------------------------------------------------------------------------------------------------------------   Cause: More shared memory is needed than was allocated in the shared pool.   Action: If the shared pool is out of memory, either use the          dbms_shared_pool package to pin   large packages, reduce your use of shared memory, or increase the amount of   available shared memory by increasing the value of the INIT.ORA parameters   "shared_pool_reserved_size" and           "shared_pool_size".

 If the large pool is out of memory, increase   the INIT.ORA  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  和更高的版本中是隐藏的。提交如下的语句查找这个参数值  :

SELECT     nam  .  ksppinm  NAME,  val  .  ksppstvl  VALUE

       FROM  x$ksppi nam  ,  x$ksppsv val

      WHERE  nam  .  indx  =  val  .  indx  AND  nam  .  ksppinm  LIKE  '%shared%'

ORDER  BY  1  ;

 

2.  诊断  ORA-04031  错误

ORA-04031  可能是因为  SHARED POOL  不够大,或是因为碎片问题导致数据库不能找到足够大的内存块。

ORA-04031  错误通常是因为库高速缓冲中或共享池保留空间中的碎片。  在加大共享池大小的时候考虑调整应用使用共享的  SQL  并且调整如下的参数: SHARED_POOL_SIZE, SHARED_POOL_RESERVED_SIZE, SHARED_POOL_RESERVED_MIN_ALLOC. 首先判定是否  ORA-04031  错误是由共享池保留空间中的库高速缓冲的碎片产生的。提交下的查询: select free_space, avg_free_size,used_space, avg_used_size,request_failures, last_failure_size FROM v$shared_pool_reserved; 如果  : REQUEST_FAILURES > 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  等于  并且 LAST_FAILURE_SIZE < SHARED_POOL_RESERVED_MIN_ALLOC 那么是因为在库高速缓冲缺少连续空间导致  ORA-04031  错误。 第一步应该考虑降低  SHARED_POOL_RESERVED_MIN_ALLOC  以放入更多的对象到共享池保留空间中并且加大  SHARED_POOL_SIZE  。、

3.  解决  ORA-04031  错误

A.           ORACLE BUG  安装相应  patch

B.           共享池碎片通过  ALTER SYSTEM FLUSH SHARED_POOL

C.           增加  shared_pool_size

•  ORACLE BUG 要解决这个错误  (  如果可以称得上错误的话)  ,  进行的诊断的第一步是在你的平台上使用最新的补丁集。大多数的  ORA-04031  错误都和  BUG  相关,可以通过使用这些补丁来避免。 Oracle  推荐对你的系统打上最新的  PatchSet.  大多数的  ORA-04031  错误都和  BUG  相关,可以通过使用这些补丁来避免。

  下面表中总结和和这个错误相关的最常见的  BUG  、可能的环境和修补这个问题的补丁。

    BUG  描述    Workaround Fixed

<Bug:1397603> ORA-4031/SGA memory leak of PERMANENT memory occurs for buffer handles  _db_handles_cached = 0  901/ 8172 <Bug:1640583> ORA-4031 due to leak / cache buffer chain contention from AND-EQUAL access Not available 8171/901 <Bug:1318267> INSERT AS SELECT statements may not be shared when they should be if TIMED_STATISTICS. It can lead to ORA-4031 _SQLEXEC_PROGRESSION_COST=0  8171/8200 <Bug:1193003> Cursors may not be shared in 8.1 when they should be Not available 8162/8170/ 901 <Bug:2104071>  ORA-4031/excessive "miscellaneous" shared pool usage possible. (many PINS) None-> This is known to affect the XML parser.  8174, 9013, 9201 <Note:263791.1>  Several number of BUGs related to ORA-4031 erros were fixed in the 9.2.0.5 patchset Not available 9205

编译  Java  代码时出现的  ORA-4031

  在你编译  Java  代码的时候如果内存溢出,你会看到错误:

    A SQL exception occurred while compiling   

    ORA-04031    unable to allocate bytes of shared memory

  (  "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> .

共享池结构中的一些  BUG  会引起这个错误,不过通常大量的共享的  SQL/PLSQL  语句也会引起这个错误。一旦打过了最新的补丁,在遇到这个问题的时候建议调整数据库和应用。 •  共享池碎片 每一次,需要被执行的  SQL  或者  PL/SQL  语句的解析形式载入共享池中都需要一块特定的连续的空间。数据库要扫描的第一个资源就是共享池中的空闲可用内存。一旦空闲内存耗尽,数据库要查找一块已经分配但还没使用的内存准备重用。如果这样的确切尺寸的大块内存不可用,就继续按照如下标准寻找:   大块  (chunk)  大小比请求的大小大   空间是连续的   大块内存是可用的  (  而不是正在使用的  ) 这样大块的内存被分开,剩余的添加到相应的空闲空间列表中。当数据库以这种方式操作一段时 间之后,共享池结构就会出现碎片。 当共享池存在碎片的问题  ,  分配一片空闲的空间就会花费更多的时间  ,  数据库性能也会下降  (  整个操作的过程中,  "chunk allocation"  被一个叫做  "shared pool latch"  的闩所控制  或者是出现  ORA-04031  错误  errors (  在数据库不能找到一个连续的空闲内存块的时候  )  ------------------------------------------------------------------------------------- 参考  <Note:61623.1>:  可以得到关于共享池碎片的详细讨论。 ------------------------------------------------------------------------------------- 如果  SHARED_POOL_SIZE  足够大,大多数的  ORA-04031  错误都是由共享池中的动态  SQL  碎片导致的。可能的原因如下:   非共享的  SQL   生成不必要的解析调用  (  软解析  )   没有使用绑定变量 要减少碎片的产生你需要确定是前面描叙的几种可能的因素。可以采取如下的一些方法,当然不 只局限于这几种  应用调整、数据库调整或者实例参数调整。 -------------------------------------------------------------------------------------- 请参考  <Note:62143.1>  ,描述了所有的这些细节内容。这个注释还包括了共享池如何工作的细节。 -------------------------------------------------------------------------------------- 下面的视图有助于你标明共享池中非共享的  SQL/PLSQL  • V$SQLAREA  视图  这个视图保存了在数据库中执行的  SQL  语句和  PL/SQL  块的信息。下面的  SQL  语句可以显示给你带有  literal  的语句或者是带有绑定变量的语句:

SELECT   SUBSTR (sql_text, 1, 40) "SQL", COUNT (*),          SUM (executions) "TotExecs"     FROM v$sqlarea    WHERE executions < 5 GROUP BY SUBSTR (sql_text, 1, 40)   HAVING COUNT (*) > 30 ORDER BY 2;

  注:  Having  后的数值  "30"  可以根据需要调整以得到更为详细的信息。

    X$KSMLRU  视图

  这个固定表  x$ksmlru  跟踪共享池中导致其它对象换出(  age out  )的应用。这个固定表可以用来标记是什么导致了大的应用。

  如果很多对象在共享池中都被阶段性的刷新可能导致响应时间问题并且有可能在对象重载入共享池中的时候导致库高速缓冲闩竞争问题。

  关于这个  x$ksmlru  表的一个不寻常的地方就是如果有人从表中选取内容这个表的内容就会被擦除。这样这个固定表只存储曾经发生的最大的分配。这个值在选择后被重新设定这样接下来的大的分配可以被标记,即使它们不如先前的分配过的大。因为这样的重置,在查询提交后的结果不可以再次得到,从表中的输出的结果应该小心的保存。监视这个固定表运行如下操作:

    SELECT * FROM X$KSMLRU WHERE ksmlrsiz > 0 

  这个表只可以用  SYS  用户登录进行查询。

    X$KSMSP  视图  (类似堆  Heapdump  信息)

使用这个视图能找出当前分配的空闲空间,有助于理解共享池碎片的程度。如我们在前面的描述,查找为游标分配的足够的大块内存的第一个地方是空闲列表(  free list  )。  下面的语句显示了空闲列表中的大块内存:

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$ksmsp      WHERE 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$ksmsp      WHERE 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$ksmsp      WHERE 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$ksmsp      WHERE 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$ksmsp      WHERE ksmchsiz >= 4108 AND ksmchcls = 'free'   GROUP BY ksmchcls, 1000 * TRUNC (ksmchsiz / 1000);

 

•  小的共享池尺寸 最后  ,  一个小的共享池可以导致  ORA-04031  错误  不过在碎片真正的是个问题的时候增大 共享池的大小的时候要小心。在错误发现的时候通常有延迟现象,不过当在大的共享池的 碎片中找到一片空闲的内存会加大对性能的影响。 下面的信息将有助于你调整共享池的大小: 库高速缓冲命中率 命中率有助于你衡量共享池的使用,基于多少次  SQL/PLSQL  需要被解析而不是 重用。下面的  SQL  语句有助于你计算库高速缓冲的命中率: select SUM(PINS) "EXECUTIONS", SUM(RELOADS) "CACHE MISSES WHILE EXECUTING" FROM V$LIBRARYCACHE; 如果  misses  比上  executions  大于  1%,  那就应该尝试着通过加大共享池来减少库高速缓冲 的丢失。 Shared Pool Size Calculation 要计算最适合当前工作负荷的共享池大小,参考: <Note:1012046.6>: HOW TO CALCULATE YOUR SHARED POOL SIZE.

4    ORA-04031  和共享池刷新

有一些技巧会提高游标的共享能力,从而共享池碎片和  ORA-4031  都会减少。最佳途径是调整应用使用绑定变量。另外在应用不能调整的时候考虑使用  CURSOR_SHARING  参数和  FORCE  不同的值来做到  (要注意那会导致执行计划改变,所以建议先对应用进行测试)。当上述技巧都不可以用的时候,并且碎片问题在系统中比较严重,刷新共享池(  alter system flush SHARED_POOL  )可能有助于减轻碎片问题。但是,必须加以如下考虑:

  刷新将导致所有没被使用的游标从共享池删除。这样,在共享池刷新之后,大多数  SQL    PL/SQL  游标必须被硬解析。这将提高  CPU  的使用,也会加大  Latch  的活动。

  当应用程序没有使用绑定变量并被许多用户进行类似的操作的时候(如在  OLTP  系统中)  ,刷新之后很快还会出现碎片问题。所以共享池对设计糟糕的应用程序来说不是解决办法。

  对一个大的共享池刷新可能会导致系统挂起,尤其是实例繁忙的时候,推荐在非高峰的时候刷新

5.    ORA-04031  的高级分析 如果使用如上的解决办法,这个错误仍然出现,在  initSID.ora  文件中设定如下的事件并重新启动实例: event = "4031 trace name errorstack level 3" 会在下一次错误发生的时候产生一个跟踪文件。 这个跟踪文件可以提供给  Oracle  支持人员来解决问题。

相关推荐