
linux 内存占用高,不能只看 free -h 的“used”值就断定有问题——Linux 会尽可能利用空闲内存做缓存(buffers/cache),这部分在需要时可立即回收。真正要关注的是是否发生了频繁换页、OOM Killer 是否被触发、以及哪些进程或内核对象长期占用了不可回收内存。
第一步:确认是否真存在内存压力
运行以下命令快速判断:
-
free -h:重点关注 available 列(内核 3.14+ 提供),它表示当前可立即分配给新进程的内存,比 “used” 更具参考价值;若 available 长期接近 0,才说明有真实压力。 -
cat /proc/meminfo | grep -E "^(MemAvailable|SwapTotal|SwapFree|OomKillCount)":检查 MemAvailable 是否持续偏低、Swap 是否被大量使用、OomKillCount 是否非零(说明 OOM 已发生)。 -
vmstat 1 5:观察 si(swap in)和 so(swap out)是否持续大于 0,以及 bi/bo(块设备 I/O)是否异常高——这往往意味着内存不足导致频繁换页或缓存抖动。
第二步:定位高内存消耗的用户进程
优先排查用户态进程:
-
ps aux --sort=-%mem | head -10:按内存使用率倒序列出前 10 个进程,注意看 RSS(常驻内存集)和 %MEM。 -
top或htop(需安装):按 M 键按内存排序,实时观察 RSS 和 VIRT 变化;留意进程状态(如 D 状态可能因等待 I/O 卡住并持有内存)。 - 对可疑进程进一步分析:
pmap -x <pid></pid>查看其内存段分布;cat /proc/<pid>/status | grep -E "^(VmRSS|VmSize|MMUPageSize|RssAnon|RssFile)"</pid>区分匿名内存(堆/栈)和文件页(如 mmap 的共享库)。
第三步:检查内核内存与特殊内存占用
当用户进程 RSS 总和远低于 total used,问题往往出在内核侧:
-
slabtop:查看内核 slab 分配器占用,重点关注 cache 列中排名靠前的项(如 dentry、inode、ext4_inode_cache、kmalloc-*)。若某 cache 持续增长且不释放,可能是文件系统句柄泄漏或内核模块异常。 -
cat /proc/meminfo | grep -E "^(SReclaimable|SUnreclaim|PageTables|KernelStack|CommitLimit|Committed_AS)":SReclaimable 是可回收的 slab(如 dentry/inode 缓存),SUnreclaim 是不可回收的(如某些驱动分配的内存);PageTables 和 KernelStack 过大可能暗示进程数过多或内核栈泄漏。 -
find /sys/kernel/slab/ -name 'slabs' -exec sh -c 'echo {} ; cat {}/slabs' ; 2>/dev/NULL | sort -k2 -nr | head -10:辅助定位高 slabs 数量的 cache。
第四步:识别隐性内存大户:内存映射与大页
某些内存不体现在进程 RSS,但实际占用物理页:
-
grep -i "mmapped" /proc/*/smaps 2>/dev/null | awk '{sum += $2} END {print sum " kB"}':粗略统计所有进程 mmap 的内存总量(含共享库、mmap 文件、hugepage 映射等)。 -
cat /proc/meminfo | grep -i "huge":检查 HugePages_Total / Free,若应用未启用 hugetlb,却有大量已分配 hugepage,可能是配置残留或内核参数误设(如 vm.nr_hugepages 设置过大)。 -
ls -l /dev/shm /run /var/run:检查 tmpfs 挂载点(如 /dev/shm)是否被写入大量数据(例如 redis 持久化到 shm、容器 runtime 临时文件堆积)。
排查不是线性流程,常需交叉验证。比如发现 slab 占用高,同时 lsof +L1 显示大量被删除但仍打开的文件,就可能指向 dentry/inode 泄漏;又如 Committed_AS 接近 CommitLimit,即使 available 尚可,也预示着 fork 大量进程时可能触发 OOM。核心是理解 Linux 内存管理机制,再结合指标找矛盾点。