Ora-04031作为数据库较为典型的内存分配错误,它的出现往往意味着数据库的无法使用直接影响用户生产系统的正常运作。
发现在几天前数据库就已经在不停的自动进行内存分配的调整,不断减小buffer_cache,来增大shared_pool,那问题来了,是什么原因导致shared_pool不断增大,仍然出现了内存不够分配的情况。
最近就遇到了一例,环境如下:
数据库版本:Oracle 11.2.0.3
操作系统:AIX 6.1
物理内存: 64G
数据量:300G左右
错误现象: 应用无法连接数据库,数据库无响应
通过检查后台日志发下报错信息如下:
Errors in file/oracle/diag/rdbms/orcl/orcl/trace/orcl_ora_17760806.trc (incident=482899):
ORA-04031: 无法分配 1016 字节的共享内存 ("shared pool","unknownobject","sga heap(1,1)","KGLHD")
而64M的buffer_cache对于一个300G左右数据量的数据库显然是不合理的,此时的bufferhit只有37%,一般来说buffer hit至少要在90%以上才算正常。
继续检查各个内存参数,分配给oracle的总内存memory_max_target=38G,其中pga=5G,db_cache=10g,shared_pool=20G,而memory_target和sga_target都为0,正常来说数据库应该为手动管理,即各个内存区域设置后不应该自动调整状态,为什么会自动进行调整,这一点还有待进一步验证。
通过查询
SELECT start_time, end_time, component, oper_type, oper_mode,initial_size, target_size, final_size, status FROMdba_hist_memory_resize_ops ORDER BY 1, 2;

发现在几天前数据库就已经在不停的自动进行内存分配的调整,不断减小buffer_cache,来增大shared_pool,那问题来了,是什么原因导致shared_pool不断增大,仍然出现了内存不够分配的情况。
继续查看相关AWR
其中freememory还有非常多的空间,由于为了用户尽快能够使用,数据库已经进行了重启,无法获得当时的内存堆栈情况;
检查数据库相关SQL语句,应用语句基本上都没有使用绑定变量,同时cursor_sharing设置为similar,当cursor_sharing设置为similar容易造成数据库的一些问题类似于latch和pin发生的时间增多,内存碎片化严重无法回收,甚至于一些bug,12c中已经取消了该参数similar的设置,当然设置为force也会带来一定的问题,针对此类情况最好的方法是通过应用修改程序,使用绑定变量可以从根本上有效解决shared_pool过度分配的情况。
再看KGLHD也占用了相当大的空间,记忆中MOS上曾经看到过类似的文章,
当 _KGHDSIDX_COUNT>1,而KGLHD又占用较高,出现ORA-04031错误,即使通过flushshared_pool也无法释放相关内存空间,这些现象下,可能是由于bug引起的。
_KGHDSIDX_COUNT参数是什么?
Oracle 9i之前,shared_pool太大的情况下,会由于shared_pool free list 或者 usedlist太长造成一些性能问题。Oracle 9i开始,增加了shared_pool subpool的概念,一个大的shared_pool,会被分割成几个sub pool,每个sub pool有自己的free list,used list. 这样,就不会因shared_pool太大造成性能问题。
sub pool的数量通常是默认的,Oracle根据shared pool大小决定的,也可以由 _kghdsidx_count来决定。
通过语句,检查_KGHDSIDX_COUNT的值为4。
select a.ksppinm, b.ksppstvlfrom x$ksppi a, x$ksppsvb
where a.indx = b.indx and a.ksppinm ='_kghdsidx_count';
再次通过MOS进行比对,此次错误情况的确符合Bug: 13250244的描述
Oracle官方给出的说法在12c版本中进行了修复
当前状态下可以通过
1)升级到11.2.0.4,或安装11.2.0.3.4补丁。
2)修改隐含参数(需重启数据库生效)来应对ora-04031的错误
ALTERSYSTEM SET "_kghdsidx_count"=1 SCOPE=SPFILE;
进行此bug的应对,但是修改参数可能导致内存shared_pool和librarycache争用的情况影响运行性能。
至此问题基本可以明确,由于未使用绑定变量的情况下,修改cursor_sharing参数可能导致的oraclebug,解决此问题的思路为:
1)应用厂商修改程序,使用绑定变量,并修改cursor_sharing参数,改回默认的exact;
2)安装补丁或升级到11.2.0.4版本;
3)增加物理内存(不能根除问题),扩大oracle可用内存空间;
4)定期重启数据库释放空间。
日常观察和预防该错误的手段,可以使用:
selectfree_space,avg_free_size,used_space,avg_used_size,request_failures,last_failure_size
from v$shared_pool_reserved;
from v$shared_pool_reserved;
当request_failures > 0 那说明shared_pool 在内存分配上已经存在一定的问题。