查pga占用不能只看单次ash采样值,因其是瞬时快照而非累计值;需结合连续采样、v$process实时指标、内存管理模式及后台进程行为综合判断。
查pga_allocated不能只看单次采样值
pga_allocated在v$active_session_history里是每秒一次的瞬时快照,不是累计值。你看到某行是800mb,不代表这会话“总共用了800mb”,更不说明它一直占着——可能前一秒刚申请,后一秒就释放了。11g中dba_hist_active_sess_history甚至不存这个字段,回溯能力极弱;12c+才支持历史聚合。
- 别直接用
SELECT * FROM V$ASH WHERE pga_allocated > 500*1024*1024找“大内存会话”,容易误判短时峰值 - 重点看同一
session_id在连续多个采样点(比如5分钟内)反复出现高值,才说明驻留占用 - 若
sql_id为空且program含ora_mmon、ora_d000、ora_cjq0,基本可排除前台SQL,是后台进程在持续吃PGA
区分前台SQL和后台进程的真实消耗
AWR报告里的“SQL ordered by PGA Memory”只统计前台SQL的工作区,漏掉INMEMORY解压缓冲、DBMS_SQL.PARSE、AWR快照收集等后台PGA开销。真要定位,得把ASH和后台进程行为对上号。
- 执行:
SELECT program, event, COUNT(*) c FROM v$active_session_history WHERE sample_time > SYSDATE - 1/24 AND pga_allocated > 100*1024*1024 GROUP BY program, event ORDER BY c DESC - 如果
program是ora_mmon_*且event是latch: shared pool,大概率是MMON在做自动内存监控或共享池清理,不是应用问题 - 如果
event是gc current block 2-way或enq: TX - row lock contention,说明Cache Fusion争用触发大量PL/SQL解析——这部分内存走PGA但不计入V$SQL_WORKAREA
结合V$PROCESS验证实时驻留量
V$PROCESS.pga_alloc_mem和V$PROCESS.pga_used_mem才是当前真实驻留指标,单位字节,会话退出即清零。它和ASH互补:ASH帮你回溯“谁曾经吃得多”,V$PROCESS告诉你“谁现在还没吐出来”。
- 查当前Top 5:
SELECT spid, program, pga_alloc_mem/1048576 mb FROM v$process ORDER BY pga_alloc_mem DESC FETCH FIRST 5 ROWS ONLY - 注意
pga_used_mem比pga_alloc_mem更接近实际占用,差值大的进程可能有未释放的PL/SQL变量或游标 - RAC环境必须按
SID单独查,ora_mmon_rac1和ora_mmon_rac2的内存行为可能完全不同
别跳过内存管理模式确认这一步
没先确认AMM还是ASMM,所有后续分析都可能跑偏。_pga_aggregate_limit在AMM下才生效,ASMM下被忽略;而pga_aggregate_target只是Oracle估算workarea大小的基数,不是硬上限。
- 先跑:
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完全无效
真正难的不是查出哪个进程占得多,而是判断它该不该占这么多——后台进程长期持有几百MB PGA,往往意味着配置错配或功能异常,而不是简单kill session能解决的。











