记一次ORA-4030错误的分析过程-解密Linux下Oracle单个进程申请内存限制

2020-08-10 00:00:00 数据库 参数 内存 进程 申请


这是一次日常巡检中发现的问题,一般遇到ORA-错误都要分析下原因,看看对数据库还是对业务运行是否有影响,告警日志报错如下

ORA-04030: out of process memory when trying to allocate 169040 bytes (pga heap,kgh stack)

ORA-04030: out of process memory when trying to allocate 127000 bytes (QERHN hash-joi,kllcqas:klls

从报错信息看是进程内存不足导致的异常,对业务数据有哪些影响还是不清楚,于是我使用oerr ora 4030查了下错误含义

Cause: Operating system process private memory was exhausted,

Oracle提示以及oerr信息看是私有内存不足,也就是PGA大小不够了。也就是说某个用户执行SQL,这个SQL需要使用PGA内存,但是这个需要申请的内存大小超过了Oracle可以提供的大小,也就是Oracle在这里有资源限制。于是我自然想到查询PGA参数设置信息

SQL> show parameter pga;

 

NAME                                 TYPE        VALUE

------------------------------------ ----------- ------------------------------

_pga_max_size                         big integer 60G

pga_aggregate_limit                     big integer 0

pga_aggregate_target                    big integer 40G

 

如果细心你会发现有一个隐藏参数_pga_max_size,该参数的含义每个进程使用PGA的大值。也就是用户在某个时间曾经修改过这个隐藏参数,但是目前看这个参数没有效果。这里我们其实可以猜测,很可能Oracle对每个进程申请的内存做了限制,其实可以反向思考,如果没有限制,如果某个SQL异常,多少内存都不够用,或许Oracle早就挂了,这样对整体系统的稳定性也有影响。我们进一步分析OraclePGA分配情况

SQL> select name,value/1024/1024/1024 "Gbytes" from v$pgastat;        

 

NAME                                         Gbytes

---------------------------------------- ----------

aggregate PGA target parameter                   40

aggregate PGA auto target                34.0423737

global memory bound                               8

total PGA inuse                          2.17521286     <== current PGA usage

total PGA allocated                       2.8698864     <== current PGA allocated

maximum PGA allocated                    95.2019644     <== maximum over "life" of instance

total freeable PGA memory                .308898926

这里可以看出Oracle确实大分配了过95G PGA

通过阅读几篇MOS文档,确实发现OracleLinux下数据库的单个进程分配内存受到隐藏参数设置,这个参数和操作系统参数配合使用可以调到数据库服务器进程分配的内存大小。

下面我们查询这个隐藏设置

select i.ksppinm name , v.ksppstvl cur_val,

     v.ksppstdf default_val, v.ksppstvf

     from x$ksppi i, x$ksppcv v

    where i.indx = v.indx and i.ksppinm in ('_realfree_heap_pagesize', '_use_realfree_heap')

 

NAME                           CUR_VAL                        DEFAULT_V   KSPPSTVF

------------------------------ ------------------------------ --------- ----------

_realfree_heap_pagesize        65536                          TRUE              

_use_realfree_heap             TRUE                           TRUE              

65536说明数据库RDBMS4G限制,继续操作系统查询

 more /proc/sys/vm/max_map_count

262144

262144说明操作系统用户限制16g,二者不一致做取小限制4g .也就是Oracle对单个进程申请内存收到4G大小的限制。为了验证这个问题,我们打开trc文件

REAL-FREE ALLOCATOR DUMP FOR THIS PROCESS

-----------------------------------------

Dump of Real-Free Memory Allocator Heap [0x7ffff29eb000]

mag=0xfefe0001 flg=0x5000007 fds=0x0 blksz=65536

blkdstbl=0x7ffff29eb010, iniblk=523264 maxblk=524288 numsegs=321

In-use num=128863 siz=4171431936, Freeable num=6 siz=589824, Free num=26 siz=4325376

 

trc文件中,我们可以确认限制了单个进程的内存大小 524288个块(8k= 4g .我们继续查询trc文件的内容,找到问题SQL看看他们对PGA申请的大小

-------------------------

Top 10 processes:

-------------------------

(percentage is of 46 GB total allocated memory)

70% ospid 326054      (    ): 31 GB used, 32 GB alloc, 576 KB freeable <= CURRENT PROC

23% ospid 372014      (    ): 10 GB used, 10 GB alloc, 384 KB freeable

 1% ospid 391398      (    ): 464 MB used, 464 MB alloc

 0% ospid 212162      (RMS0): 19 MB used, 80 MB alloc, 60 MB freeable

 0% ospid 355027      (    ): 50 MB used, 55 MB alloc, 896 KB freeable

 0% ospid 150316      (    ): 43 MB used, 47 MB alloc

 0% ospid 213222      (ARC0): 42 MB used, 45 MB alloc

 0% ospid 213226      (ARC1): 42 MB used, 45 MB alloc

 0% ospid 213228      (ARC2): 42 MB used, 45 MB alloc

 0% ospid 213230      (ARC3): 42 MB used, 45 MB alloc

有两个进程申请PGA内存分别为32g 10G ,这两个进程都报错。显然他们申请的内存大小都超过了4G

具体的SQL就不贴了,后面的问题就是分析SQL执行计划,看看哪里耗费PGA资源,比如排序,hash等操作,看是否可以优化,那就是另一个层面的问题(提示原始SQL中都是dblink远程表关联,这种操作往往需要远程表先传递到本地PGA操作)。

 这个问题两个解决方案:

1 修改数据库和操作系统参数,提供更大的单个进程内存

2 调优SQL减少PGA的使用,这个是优先要考虑的。

比如修改到32G

524288 <<<<<<< 32G

1 修改操作系统参数

 sysctl -w vm.max_map_count=524288

2 修改数据库隐藏参数

alter system set "_realfree_heap_pagesize"=524288


相关文章