先确认AMM/ASMM模式:若memory_target>0则为AMM,_pga_aggregate_limit才生效;若仅sga_target和pga_aggregate_target>0则为ASMM,此时PGA上限由Oracle动态估算,_pga_aggregate_limit被忽略。
查 V$PGASTAT 前先确认 AMM/ASMM 模式是否启用
ora-04036 或节点内存持续上涨,八成不是真泄漏,而是 memory_target 或 sga_target/pga_aggregate_target 配置与负载错配。不先确认内存管理模式,后续所有分析都可能方向错误。
- 执行
SELECT name, value FROM v$parameter WHERE name IN ('memory_target', 'sga_target', 'pga_aggregate_target'); - 若
memory_target > 0,则为 AMM 模式,_pga_aggregate_limit才可能生效;设了pga_aggregate_target就会退回到 ASMM,该隐含参数直接被忽略 - 若只有
sga_target > 0且pga_aggregate_target > 0,则是 ASMM,此时 PGA 上限由 Oracle 动态估算,_pga_aggregate_limit不参与硬限制 - RAC 中每个实例必须单独检查——
SID='rac1'和SID='rac2'的结果可能完全不同
用 AWR 报告定位 PGA 消耗峰值与趋势
单看某时刻的 V$PGASTAT 容易误判,AWR 能暴露周期性高峰和后台进程“偷吃”行为。
- 生成最近 2 小时的 AWR 报告:
awrrpt.sql(在 SQL*Plus 中运行),重点关注 “Instance Efficiency Percentages” 下的 “PGA Hit %” 和 “Memory Sorts %” - 翻到 “SQL Statistics” → “SQL ordered by PGA Memory”,但注意:这部分只统计前台 SQL 工作区,**不包含 INMEMORY 解压缓冲区、DBMS_SQL.PARSE、AWR 快照收集等后台 PGA 消耗**
- 重点看 “Background Processes” 部分:若
ora_mmon_*、ora_d000_*、ora_cjq0_*在 “PGA Memory” 列排进 Top 5,说明 GC 协调、作业队列或自动内存监控正在大量分配 PGA - 对比连续几个 AWR 报告中
total PGA allocated的增长斜率——如果每小时稳定涨 1.2GB 且无对应业务高峰,大概率是未关闭的统计任务或 INMEMORY 持续预热
用 ASH 实时抓取高 PGA 占用的非前台进程
V$SESSION 查不到大 PGA 进程?ASH 能穿透后台进程堆栈,暴露真实消耗源。
- 执行:
SELECT session_id, session_serial#, program, pga_allocated/1024/1024 MB, event, sql_id FROM v$active_session_history WHERE pga_allocated > 200*1024*1024 AND sample_time > SYSDATE - 1/24 ORDER BY pga_allocated DESC; - 重点关注
program字段含ora_mmon、ora_d000、ora_cjq0的行——这些进程的 PGA 消耗常在 AWR 中被平滑掉,但在 ASH 里能精确到秒级 - 若
event是gc current block 2-way或enq: TX - row lock contention,说明 Cache Fusion 争用触发了大量 PL/SQL 解析,而解析内存走 PGA,且不计入V$SQL_WORKAREA - 配合
V$INMEMORY_AREA查 INMEMORY 影响:SELECT bytes_used, bytes_not_populated FROM v$inmemory_area;若差值长期 > 5GB,说明解压缓冲区已成 PGA 主力消耗项
验证 _PGA_AGGREGATE_LIMIT 是否真起作用
参数写进 SPFILE ≠ 生效。很多 DBA 设置后仍出 ORA-04036,是因为没验证它是否真正参与判断。
- 查当前生效值:
SELECT name, value FROM V$PGASTAT WHERE name IN ('aggregate PGA auto target', 'global memory bound');二者应接近你设的_pga_aggregate_limit值;若远低于,说明未启用 AMM 或被 ASMM 覆盖 - 手动触发测试(仅限非生产):
DECLARE TYPE t_tab IS TABLE OF VARCHAR2(32767) INDEX BY PLS_INTEGER; l_data t_tab; BEGIN FOR i IN 1..500000 LOOP l_data(i) := RPAD('x', 1000, 'x'); END LOOP; END;—— 若报 ORA-04036,说明限制已生效;若只报 ORA-04030,则限制未接管 - RAC 必须逐节点验证:
SELECT name, value FROM V$SPPARAMETER WHERE name = '_pga_aggregate_limit' AND sid = 'rac1';,不能只查当前实例 - 注意:12cR2+ 中该值默认动态计算,即使你设了 8G,Oracle 可能按物理内存 × 0.25 自动下调——所以最终生效值未必等于你写的数字
最易被忽略的是 INMEMORY 解压缓冲区和后台进程的 PGA 计入逻辑——它们不走 SQL 工作区路径,也不响应传统 PGA 调优手段,却能在 10 分钟内吃掉 4GB。排查时别只盯着 V$SQL_WORKAREA 和前台会话。











