Linux 内存占用逐步升高的排错思路

9次阅读

linux cached内存可自动回收,关键看MemAvailable是否持续逼近0及OOM Killer日志;需排查overcommit设置、cgroup限制、NFS缓存、句柄泄漏及业务变更点。

Linux 内存占用逐步升高的排错思路

内存占用持续上涨但 free 显示有大量 cached

Linux 的 cached 内存(页缓存)本就是可回收的,只要应用需要,内核会自动释放。别一看到 free -havailable 值低就断定“内存泄漏”。关键看 available 是否持续逼近 0,以及是否有进程因 OOM 被杀——这才是真压力。

实操建议:

  • free -havailable 列,不是 free
  • 运行 watch -n 1 'free -h; echo; cat /proc/meminfo | grep -E "^(MemAvailable|Cached|SReclaimable)"; echo; ps aux --sort=-%mem | head -5' 持续观察趋势
  • Cached 高但 SReclaimable 占比低(比如 MADV_DONTNEED 或文件被锁)

确认是否存在用户态内存泄漏:用 pmap/proc/[pid]/smaps

单个进程 RSS 持续增长,且不随业务负载下降而回落,才值得怀疑泄漏。不要只看 top 的 %MEM 排序——它按比例算,小进程占比高但绝对值未必大。

实操建议:

  • 先用 ps aux --sort=-rss | head -10 找 RSS 最大的进程,再查其 pmap -x [pid],关注 mappedwritten 列是否异常增长
  • 深入看 cat /proc/[pid]/smaps | awk '/^Size:/ {sum+=$2} END {print sum}' 统计总虚拟内存;对比 Rss:Pss:,若 Rss 持续涨而 Pss 不涨,可能是共享内存或 mmap 区域在累积
  • java 进程,优先用 jstat -gc [pid] 看老年代是否持续增长且 GC 后不回落;对 go 进程,检查 GODEbug=madvdontneed=1 是否缺失(旧版 Go 默认不主动归还内存)

slabtop 显示 kmalloc-*dentry 占用飙升

内核 slab 分配器里的对象(如 dentryinodeext4_inode_cache)持续增长,往往意味着文件系统层存在资源未释放:比如程序反复 open 不 close、遍历海量小文件后未释放 dcache、或 NFS 客户端元数据缓存积。

实操建议:

  • 运行 slabtop -o(实时排序),重点关注 ACTIVENUMA 列;若 dentry > 10M 且稳定上升,用 find /proc/*/fd -ls 2>/dev/null | grep -c '->' | sort -n 查打开文件数异常的进程
  • 临时清理:echo 2 > /proc/sys/vm/drop_caches(仅清 dentry/inode 缓存,不影响 page cache);但这是治标,需配合 lsof +D /path 定位长期持有句柄的进程
  • 排查 NFS 挂载时,注意 nfsstat -cdcache 命中率,若低于 80%,可能客户端缓存策略过激,需调 acregmin/acregmax

OOM Killer 日志里反复出现同一进程被杀

这不是内存“占用高”,而是内存真的不够用了。dmesg -T | grep -i "killed process" 会显示被杀进程名、触发时的 MemAvailable 值和各内存域状态。重点不是“谁被杀”,而是“为什么只剩这点可用内存”。

实操建议:

  • 检查 /proc/sys/vm/overcommit_memory:值为 2 时启用严格 overcommit,vm.overcommit_ratio 设置过低(如默认 50)会导致大进程 malloc 失败,看似泄漏,实为限制
  • 确认是否启用了 cgroup v1 的 memory limit(cat /sys/fs/cgroup/memory/[group]/memory.limit_in_bytes),容器场景下常因配置过小导致进程被 OOM 而非真正泄漏
  • 若日志中 pgpgin/pgpgout 极高,说明频繁换入换出,可能是物理内存不足 + swap 使用过度,此时应优先关 swap(swapoff -a)并加内存,而非调优应用

最易被忽略的是:内存增长曲线和业务日志的时间戳对不上。先做时间对齐,再排除定时任务、日志轮转、监控 agent 自身 bug 这类“伪泄漏”。真实泄漏往往安静,但会在某次 deploy 后突然显现——盯紧变更点。

text=ZqhQzanResources