ORA-04031 shared_pool 不能分配足够内存或磁盘碎片

--相关链接
http://blog.csdn.net/perddy/archive/2009/08/10/4430823.aspx
白鳝DBA日记中的由于ORA-04031 导致ORA-00600

--状态描述
这个错误一般来说都是因为shared_pool 不能分配足够的内存 满足不了事务 以至于导致0RA-04031 如"unable to allocate %s bytes of shared memory

--原因总结
ORA-04031 可能是因为 SHARED POOL 不够大,或是因为碎片问题导致数据库不能找到足够大的内存块。
ORA-04031 错误通常是因为库高速缓冲中或共享池保留空间中的碎片。 在加大共享池大小的时 候考虑调整应用,使用共享的SQL 并且调整如下的参数:
    SHARED_POOL_SIZE,
    SHARED_POOL_RESERVED_SIZE,
    SHARED_POOL_RESERVED_MIN_ALLOC.

先用alter system flush shared_pool临时解决一下
fenng提供了一个sql去判断碎片的程度 如下:
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
或者  REQUEST_FAILURES 等于0 并且 LAST_FAILURE_SIZE < SHARED_POOL_RESERVED_MIN_ALLOC

这时候就需要去调整了
官方文档Diagnosing and Resolving Error ORA-04031 [ID 146599.1]详解关于ORA-04031的 如下:把所有可能产生ORA04031的原因都讲到了还列举了很多bug和解决方法。不过现在10g已经很普遍了ora-04031的错误应该不多了。

--解决方法

  • Oracle Bug, Java 内存溢出
  • 共享池尺寸过小
    1.库高速缓冲命中率:命中率有助于你衡量共享池的使用,有多少语句需要被解析而不是重用。下面的SQL语句有助于你计算库高速缓冲的命中率:
    SELECT SUM(PINS) "EXECUTIONS",SUM(RELOADS) "CACHE MISSES WHILE EXECUTING"  FROM V$LIBRARYCACHE; --如果丢失超过1%,那么尝试通过加大共享池的大小来减少库高速缓冲丢失。
    2.共享池大小计算 要计算最适合你工作负载的共享池大小,请参考:
    <Note:1012046.6>: HOW TO CALCULATE YOUR SHARED POOL SIZE. 
  • 共享池碎片
    每一次,需要被执行的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: unable to allocate XXXX bytes of shared memory
    ("large pool","unknown object","session heap","frame")
    1- 使用如下语句检查 V$SGASTAT ,得知使用和空闲的内存:
    SELECT pool,name,bytes FROM v$sgastat where pool = 'large pool';

    2- 你还可以采用 heapdump level 32 来 dump 大池的堆并检查空闲的大块内存的大小从大池分配的内存如果是LARGE_POOL_MIN_ALLOC 子节的整块数有助于避免碎片。任何请求分配小于LARGE_POOL_MIN_ALLOC 大块尺寸都将分配LARGE_POOL_MIN_ALLOC的大小。一般来说,你会看到使用大池的时候相对共享池来说要用到更多的内存。通常要解决大池中的ORA-4031错误必须增加 LARGE_POOL_SIZE 的大小。

重要标注: Oracle 9.2.0.5 和Oracle 10g 版本中,每次在发生ORA-4031 错误的时候会自动创建一个跟踪文件,可以在user_dump_dest 目录中找到。如果你的系统是上述的版本,你不需要再进行前面描述中的步骤。
其他版本需要:
SQL> alter session set events '4031 trace name errorstack level 3';
SQL> alter session set events '4031 trace name HEAPDUMP level 3';

--参考信息
Metalink - http://metalink.oracle.com
<Note:1012046.6> How to Calculate Your Shared Pool Size
<Note:62143.1> Understanding and Tuning the Shared Pool
<Note:1012049.6> Tuning Library Cache Latch Contention
<Note:61623.1> Resolving Shared Pool Fragmentation
<Note:146599.1>

你可能感兴趣的:(ora)