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

内存占用持续上涨但 free 显示有大量 cached
Linux 的 cached 内存(页缓存)本就是可回收的,只要应用需要,内核会自动释放。别一看到 free -h 里 available 值低就断定“内存泄漏”。关键看 available 是否持续逼近 0,以及是否有进程因 OOM 被杀——这才是真压力。
实操建议:
- 用
free -h看available列,不是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],关注mapped和written列是否异常增长 - 深入看
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 分配器里的对象(如 dentry、inode、ext4_inode_cache)持续增长,往往意味着文件系统层存在资源未释放:比如程序反复 open 不 close、遍历海量小文件后未释放 dcache、或 NFS 客户端元数据缓存堆积。
实操建议:
- 运行
slabtop -o(实时排序),重点关注ACTIVE和NUMA列;若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 -c中dcache命中率,若低于 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 后突然显现——盯紧变更点。










