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

诊断和解决ORA-04031错误

原创 Eygle 2019-07-24
1851

Oracle 9iR2开始引入了段级统计信息(segment statistics)收集的新特性,其中一个新引入的视图是v$segstat,查询该视图会引发Shared Pool的内存泄露(在9201~9206版本中都存在此问题,本案例测试来自Windows平台9206),我们可以利用这一问题来模拟ORA-00431错误(该Bug在Oracle 10g中已经修正,所以以下方法并不适用于Oracle 10g)。

以下是一段测试代码:

set heading off
column what format a40
column value format a30
 
select 'db instance' what, user || '@' || global_name value from global_name
UNION
select '# rows in v$segstat', to_char(count(*)) from v$segstat;
 
set linesize 200
set time on
set serveroutput on size 300000
 
declare
  l_temp        char(1);
  l_before      number;
  l_after       number := 0;
  l_loop_times  pls_integer := 1000;    -- try 1000
  l_sleep       number   := 0.00;    -- makes no difference
 
  cursor c_seg is select * from v$segstat;
  r_seg  c_seg%ROWTYPE;
 
   function get_mem return number is
     cursor c_mem is select bytes from v$sgastat
        where name = 'free memory' and pool = 'shared pool';
     r_mem   c_mem%ROWTYPE;
     begin
       open c_mem; fetch c_mem into r_mem; close c_mem;
       return r_mem.bytes;
     end get_mem;
begin
  l_after := get_mem();  
 
  for x in 1..l_loop_times loop
    l_before := l_after;
 
    OPEN c_seg; FETCH c_seg INTO r_seg; CLOSE c_seg;
 
    l_after := get_mem();
    dbms_output.put_line ('Loop ' || x || ': (' ||
       to_char(sysdate,'hh24:mi:ss') || ') from ' ||
       to_char(l_before,'999,999,999') || ' to ' ||
       to_char(l_after,'999,999,999') || ' (loss of ' ||
       to_char((l_before-l_after),'9,999,999') || ')');
    dbms_lock.sleep(l_sleep);
  end loop;
end;
/

首先来看看之前的状态(测试环境,已经把Shared Pool调整降低):

SQL> select * from v$sgastat
  2  where name in('miscellaneous','free memory') and pool='shared pool';
POOL        NAME                    BYTES
----------- -------------------------- ----------
shared pool free memory                   3927884
shared pool miscellaneous                  5752896
执行以上代码:
20:49:57 SQL> @d:\mem.leak.sql
 
# rows in v$segstat                      1034
db instance                              SYS@EYGLE
 
Loop 1: (20:50:00) from      782,072 to      769,336 (loss of     12,736)
Loop 2: (20:50:00) from      769,336 to      949,276 (loss of   -179,940)
Loop 3: (20:50:00) from      949,276 to      978,872 (loss of    -29,596)
Loop 4: (20:50:00) from      978,872 to      970,436 (loss of      8,436)
Loop 5: (20:50:00) from      970,436 to      962,012 (loss of      8,424)
Loop 6: (20:50:00) from      962,012 to      949,364 (loss of     12,648)
Loop 7: (20:50:00) from      949,364 to      946,280 (loss of      3,084)
Loop 8: (20:50:00) from      946,280 to      993,064 (loss of    -46,784)
Loop 9: (20:50:00) from      993,064 to      984,640 (loss of      8,424)
Loop 10: (20:50:00) from      984,640 to    1,092,628 (loss of   -107,988)
declare
*
ERROR at line 1:
ORA-04031: unable to allocate 4212 bytes of shared memory ("shared pool","unknown object","sga heap(1,0)","obj stat memor")
ORA-06512: at line 26
 
20:50:10 SQL>  alter session set events 'immediate trace name heapdump level 2';
 
Session altered.
20:50:20 SQL> select * from v$sgastat
20:50:20   2  where name in('miscellaneous','free memory') and pool='shared pool';
 
shared pool free memory                    888268
shared pool miscellaneous                 10144656

转储共享内存,可以看到:

……
Bucket 248 size=3948
  Chunk 7b69b5a0 sz=     3956    free      "               "
  Chunk 7b6d16b4 sz=     3956    free      "               "
 Bucket 249 size=4012
  Chunk 7b5da178 sz=     4064    free      "               "
  Chunk 7b66360c sz=     4060    free      "               "
  Chunk 7b554204 sz=     4060    free      "               "
  Chunk 7b6e2af4 sz=      4060    free      "               "
  Chunk 7b76b8b4 sz=     4052    free      "               "
 Bucket 250 size=4108
 Bucket 251 size=8204
 Bucket 252 size=16396
 Bucket 253 size=32780
 Bucket 254 size=65548
Total free space   =   180396

当前最大的Chunk size是4052,所以请求4212 时出现了04031错误。

如果系统的ORA-04031错误通常都是在4200左右出现,如前文提到的,可以通过修改_shared_pool_reserved_min_alloc参数设置减少04031错误的出现,可以比较一下。

(1)缺省情况下,_shared_pool_reserved_min_alloc = 4400,在04031错误情况下,来看一下保留池的使用:

RESERVED FREE LIST:
  Chunk 7a000038 sz=    85940  R-free      "               "
  Chunk 7a400038 sz=    85940  R-free      "               "
  Chunk 7a800038 sz=    85940  R-free      "               "
  Chunk 7ac00038 sz=    85940  R-free      "               "
  Chunk 7b000038 sz=    85940  R-free      "               "
  Chunk 7b400038 sz=    85940  R-free      "               "
Total reserved free space   =   515640

保留池保留了85940的Chunk Size,未被使用。

(2)修改_shared_pool_reserved_min_alloc = 4100,在04031错误情况下,来看一下保留池的使用。

修改方式如下,修改参数后需要重新启动数据库:

21:01:43 SQL> alter system set "_shared_pool_reserved_min_alloc"=4100 scope=spfile;
System altered.

修改后保留池的使用情况:

RESERVED FREE LIST:
  Chunk 7b414994 sz=     1624  R-free      "               "
  Chunk 7b014994 sz=     1624  R-free      "               "
  Chunk 7ac14988 sz=     1636  R-free      "               "
  Chunk 7a814994 sz=     1624  R-free      "               "
  Chunk 7a414988 sz=     1636  R-free      "               "
  Chunk 7a014994 sz=     1624  R-free      "               "
Total reserved free space   =     9768

可以看到,在修改了_shared_pool_reserved_min_alloc参数以后,保留池的使用更为充分,从而使得ORA-04031错误的出现得以延迟。

提示:本例提供一种方法模拟ORA-04031错误,你可以在测试环境中模拟和研究04031问题,但是严禁在生产环境中使用。


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

评论