ORA-04030和ORA-04031是oracle内存管理中司空见惯的错误,一个发生在pga中,一个发生在shared pool中。
关于该类错误的bug着实不少,抛却bug本身,一个稳定系统出现该类错误,很可能是code本身的问题造成了内存上的消耗或者碎片,由于无法申请可用内存,造成错误本身。
前几天有套系统的新上线模块的一个job会时不时的抛出ora-04030的错误,系统是32bit的,比较容易想到的就是可能是内存参数设置本身不合理,造成了32bit架构的内存寻址限制。实际情况并非如此。
检查sga和pga参数
sga_target big integer 800M
pga_aggregate_target big integer 300M
该job运行于晚上4点,当时系统并发量很小,相对来说,参数配置是安全的,可以排除空间寻址限制的问题。在查找相关bug的同时,怀疑编码本身可能造成了的大量的PGA空间申请,比如一些类数组结构(PL/SQL nested table,varry等),因为这部分结构是在PGA中申请,但不受到pga_aggregate_target参数限制(pga_aggregate_target控制的是SQL work area区域),因此如果代码编写不规范,很容易造成内存的过度分配。
检查代码发现,代码中声明了一个index-by table,利用bulk collect将某个业务表的数据填充到这个数组结构中,由于开发人员在测试环境中数据量不够且没有考虑到此问题,忽略使用了Limit参数,因此在生产环境中当符合业务规则数据比较多的时候,系统不断从pga中申请内存用来分配给index-by table使用,从而最终造成内存寻址的限制而抛出异常。
修改代码后,增加bulk collect的limit限制,问题得到解决。
很多朋友对pga的认识存在误区(相对sga来讲,pga对确是容易被忽略的部分),认为有了参数和隐含参数的控制,单个进程的pga申请(主要指排序和散列等受到自动管理控制的内存部分)可以控制到我们的理想取值内,但如果涉及到一些PL/SQL和JAVA申请内存结构,这部分在数据库中是不可控制的,这取决与代码的良好规范编写。如果看到用户进程用了比参数设置本身高的多的内存,所以千万不要吃惊。
接下来使用object table简单模拟一下狂吃PGA内存的进程,因为我的os是32bit的,因此也可以很容易的看到ORA-04030。参数配置如下:
sga_target=300M / pga_aggregate_target=100M
CREATE OR REPLACE TYPE pga_type AS OBJECT
(
id NUMBER,
name char(2000)
);
/
create or replace type t_pga_table as table of pga_type;
/
create or replace procedure proc_test_pga as
v_pga t_pga_table := t_pga_table();
begin
loop
v_pga.extend();
v_pga(v_pga.count) := pga_type(1, ‘pga_test’);
end loop;
end;
/
执行procedure
SQL>exec proc_test_pga ;
持续观察进程使用的pga内存:
SQL> select * from v$process_memory where pid=18;
PID SERIAL# CATEGORY ALLOCATED USED MAX_ALLOCATED
———- ———- ————— ———- ———- ————-
18 42 SQL 5056 1668 190192
18 42 PL/SQL 26828 22424 26828
18 42 Other 911965 991965
SQL> /
PID SERIAL# CATEGORY ALLOCATED USED MAX_ALLOCATED
———- ———- ————— ———- ———- ————-
18 42 SQL 5056 1668 190192
18 42 PL/SQL 26828 22424 26828
18 42 Other 1494834333 1494834333
SQL> /
PID SERIAL# CATEGORY ALLOCATED USED MAX_ALLOCATED
———- ———- ————— ———- ———- ————-
18 42 SQL 5056 1668 190192
18 42 PL/SQL 26828 22424 26828
18 42 Other 2715376797 2715376797
可以看到pga已经申请了2.7G左右的内存。这部分内存并不属于SQL workarea ,因此并不受PGA自动管理控制。
一段时间后,过程报错:
ORA-04030: out of process memory when trying to allocate 16396 bytes (koh-kghucall ,pl/sql vc2)
|
|