4.7.5 OOM机制与内存泄漏排查

本节聚焦 Linux 的 OOM 触发机制与内存泄漏排查方法,目标是理解系统在内存耗尽时的决策过程,掌握快速定位高风险进程与泄漏根因的手段,并形成可操作的处置流程。

文章图片

一、OOM 触发条件与判定逻辑
当物理内存与可回收页缓存不足、且交换空间耗尽或被限制时,内核会触发 OOM Killer。判定通常基于以下要素:
- 进程内存占用(RSS、匿名页、共享页)
- 进程优先级与 oom_score_adj(越大越容易被杀)
- 系统当前内存回收效果与失败情况
- cgroup 限制下的局部 OOM(容器常见)

关键日志定位与解释示例

# 1) 快速查看内核OOM日志(含被杀进程与分值)
dmesg -T | egrep -i 'out of memory|killed process'

# 2) 查看系统日志(不同发行版路径可能不同)
grep -i 'out of memory' /var/log/messages
grep -i 'killed process' /var/log/kern.log

预期效果:输出包含 Out of memoryKilled process <pid> 的记录,可定位具体进程与时间。

二、OOM 排查与处置流程(含命令示例)
1. 确认是否 OOM

dmesg -T | tail -n 200 | egrep -i 'out of memory|killed process'

解释:从内核环形缓冲区获取 OOM 记录,确认是否被 OOM Killer 触发。

  1. 评估全局与 cgroup 限制
# 全局内存
free -m
vmstat 1 5
cat /proc/meminfo | egrep 'MemTotal|MemFree|MemAvailable|SwapTotal|SwapFree'

# cgroup(容器/服务)
cat /sys/fs/cgroup/memory/memory.limit_in_bytes
cat /sys/fs/cgroup/memory/memory.usage_in_bytes

解释:确认是否是全局内存耗尽还是被 cgroup 限制导致局部 OOM。

  1. 识别高风险进程
# 按RSS排序
ps aux --sort=-rss | head -n 10

# 实时观察内存增长
top -p <pid>

解释:RSS 持续增长、且与业务负载无关的进程为重点怀疑对象。

  1. 快速止血(短期缓解)
# 临时创建并启用2G swap(若磁盘充足)
fallocate -l 2G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
swapon --show

解释:在不影响业务的情况下扩展 swap,降低瞬时 OOM 风险。

  1. 根因定位与修复
    - 结合应用日志、内存快照与曲线分析定位泄漏点
    - 逐步缩小范围:进程级 → 模块级 → 代码级

三、内存泄漏排查方法(含示例与解释)
1. 基线与趋势

# 每5秒记录一次RSS到文件
while true; do
  date '+%F %T' >> /tmp/rss.log
  ps -p <pid> -o pid,cmd,rss,vsz >> /tmp/rss.log
  sleep 5
done

解释:若 RSS 单调增长且业务负载稳定,疑似泄漏。

  1. 进程级分析
# 查看映射段与匿名内存
pmap -x <pid> | tail -n 20

# 细分堆、栈、匿名页、共享库占用
grep -E 'Heap|Stack|Anon' /proc/<pid>/smaps | head -n 50

解释:匿名内存持续增加通常指向堆泄漏或缓存未释放。

  1. 句柄泄漏排查(可能间接导致内存增长)
# 统计打开文件数
ls /proc/<pid>/fd | wc -l

# 查看打开的具体文件
lsof -p <pid> | head -n 20

解释:FD 数持续增长可能引发内存与资源耗尽。

  1. 内存分配行为分析(自研可控程序)
# 观察分配热点(需安装perf)
perf top -p <pid>

解释:定位异常频繁的分配函数或模块。

工具安装示例(perf)

# RHEL/CentOS
yum install -y perf

# Ubuntu/Debian
apt-get update && apt-get install -y linux-tools-$(uname -r)

四、关键指标与判断依据(带命令)

# 进程内存:RSS/VSZ
ps -p <pid> -o pid,comm,rss,vsz

# PSS(共享内存摊分)
grep -E '^Pss:' /proc/<pid>/smaps | awk '{sum+=$2} END {print sum " KB"}'

# Swap 使用情况
free -m | egrep 'Mem|Swap'

解释:RSS 更直接反映泄漏;VSZ 仅表示虚拟地址空间;PSS 更准确评估共享内存占用。

五、常见误判与规避
- 页缓存增长buff/cache 增加不等同泄漏,需关注 MemAvailable
- GC 语言:堆扩张≠泄漏,需结合 GC 日志与堆指标
- mmap 文件常驻:需结合 smaps 判断是否可回收

六、配置与防护建议(含示例)

# 降低关键进程被杀概率(-1000最不易被杀)
echo -1000 > /proc/<pid>/oom_score_adj

# 调整 swappiness(建议10~30)
sysctl -w vm.swappiness=10
echo 'vm.swappiness=10' >> /etc/sysctl.conf

解释:合理设置 oom_score_adj 保护核心进程,降低短时峰值导致的 OOM。

七、排错清单(故障定位顺序)
1) 是否出现 Out of memory 日志
2) 是否为 cgroup 限制导致
3) 是否有单个进程 RSS 单调增长
4) 是否 FD/线程数异常增长
5) 是否为缓存/队列无上限

八、练习(实操建议)
1) 使用 stress 触发内存压力并观察 OOM 迹象

# 安装stress
yum install -y stress || apt-get install -y stress

# 触发内存压力(谨慎在测试环境)
stress --vm 2 --vm-bytes 1G --timeout 30s
dmesg -T | tail -n 50

2) 选择一个进程,记录 1 分钟 RSS 变化并判断是否稳定
3) 使用 pmapsmaps 找出该进程占用最大的内存段
4) 调整 vm.swappiness 前后对 swap 使用的影响

通过以上方法,可将 OOM 从“事后事故”转变为“可预警、可定位、可修复”的可控问题,提升系统稳定性与可维护性。