要分层定位内存占用者,先查oracle实例sga/pga实际用量,再查os层非oracle进程和共享内存段残留,避免盲目调参。

查清楚到底是谁在吃内存:别只看 top,要分层定位
单看 top 或 free -h 说“节点1内存98%、节点2才70%”,没用——你得拆开看 Oracle 进程、系统缓存、其他用户进程各自占多少。RAC 节点内存不均,80% 以上是某类进程或配置偏差导致,不是随机现象。
- 先确认 Oracle 实例实际使用的 SGA+PGA:
show parameter sga_target和show parameter pga_aggregate_target查配置;再跑SELECT SUM(pga_used_mem)/1024/1024/1024 FROM gv$process算各节点 PGA 实际用量(注意是gv$process,不是v$process) - SGA 实际分配看
SELECT inst_id, component, current_size/1024/1024 AS mb FROM gv$memory_dynamic_components,重点比对DEFAULT buffer cache、shared_pool、large_pool是否某节点明显偏大 - 查非 Oracle 进程:在 OS 层用
ps aux --sort=-%mem | head -20,特别留意 Python、Java、备份脚本等常驻进程——案例里两个alert_monitor.py就吃掉 120G 内存 - 检查共享内存段是否残留:
ipcs -m看是否有未释放的 hugepage 段,尤其当之前重启过实例但没 clean shutdown 时
SGA 分配失衡:db_cache_size 不是全局开关,别乱调
db_cache_size 是实例级参数,每个节点独立生效。有人看到节点1慢,就只给它加大 db_cache_size,结果节点1 SGA 暴涨、挤压 shared_pool,反而引发 ORA-4031 和大量硬解析,CPU 升高、GC 等待飙升——这不是均衡,是制造瓶颈。
- 查真实缓存使用:
SELECT inst_id, component, current_size FROM gv$memory_dynamic_components WHERE component = 'DEFAULT buffer cache',对比各节点值是否偏离超过 2 倍 - 如果某节点
current_size远高于配置值,说明 AMM(memory_target)在动态调整,此时手动设db_cache_size会被忽略,得先关 AMM 或调memory_max_target - 盲目加缓存前,先看
gc cr blocks received和gc current blocks received:若前者远高于后者,说明该节点读热点集中但本地缓存命中差,加db_cache_size可能缓解;若后者远高,说明写争用严重,加缓存只会加剧块传输压力 - RAC 中 buffer cache hit ratio 失效:一个节点显示 95%,但其中 40% 的 “命中” 是从其他节点拉 CR 块来的,不算真高效。更应关注
physical reads direct占比——太高说明全表扫描绕缓存,调db_cache_size没用
跨节点诊断必须逐实例执行:gv$ 视图不是魔法,inst_id 别漏
所有带 g 前缀的视图(gv$sysstat、gv$session、gv$process)都需显式过滤 inst_id 或按 inst_id 分组,否则数据混在一起,会把节点1狂发、节点2狂收的 GC 流量互相抵消,误判“整体平稳”。
- 查内存相关统计必须加
inst_id:SELECT inst_id, name, value FROM gv$sysstat WHERE name IN ('session pga memory', 'session pga memory max') - 查会话级内存占用:
SELECT inst_id, sid, serial#, program, pga_used_mem/1024/1024 AS mb FROM gv$session ORDER BY pga_used_mem DESC,一眼看出哪个节点哪个会话在吃内存 - 查 buffer cache 命中率不能只算全局:
SELECT inst_id, (SUM(decode(name,'db block gets',value,0)) + SUM(decode(name,'consistent gets',value,0)) - SUM(decode(name,'physical reads',value,0))) / NULLIF(SUM(decode(name,'db block gets',value,0)) + SUM(decode(name,'consistent gets',value,0)),0) FROM gv$sysstat GROUP BY inst_id - 漏
inst_id的典型错误:SELECT SUM(pga_used_mem) FROM gv$process—— 这个 sum 把所有节点 PGA 加一起,完全掩盖了不均问题
ADRCI 和 AWR 不能替代实时观察:滞后性会骗人
AWR 快照间隔默认 60 分钟,ADRCI 的 alert 日志也是滚动写入。当你发现节点1内存突然飙到 95%,翻 AWR 报告可能只看到“过去一小时平均 70%”,根本抓不到峰值时刻的真相。
- 紧急排查时,立刻连到高内存节点运行:
SELECT * FROM v$memory_target_advice(看 AMM 建议)、SELECT * FROM v$sgastat ORDER BY bytes DESC(看 shared_pool 内部碎片) - 用
adrci查当前节点最近 10 分钟告警:adrci> show home→adrci> set homepath diag/rdbms/<db_name>/<inst_name></inst_name></db_name>→adrci> show alert -tail 100,重点搜ORA-4030(PGA 耗尽)、ORA-4031(shared_pool 不足) - OSWatcher 数据比 AWR 更及时:检查
oswmem输出,看PageIn/PageOut是否突增、Free是否跌破 5%——这是内存真正吃紧的铁证,不是“使用率高”这种模糊指标 - 别信“自动均衡”:Oracle 不会把 PGA 从节点1挪到节点2。内存不均要么是应用连接分布不均(全连 VIP 而非 SCAN),要么是 SQL 绑定不均(某些 SQL 总在节点1执行),要么是外部进程失控——得靠人工定位,不是等 Oracle 自愈
真实场景里,最常被忽略的是:内存不均往往不是 Oracle 自己的问题,而是某个监控脚本、ETL 工具或备份进程在某个节点上失控运行。查 ps 和 ipcs 比调参数快十倍。











