一句话总结
排查口诀:先 free 看 available(不是看 free!),再 top 找到吃内存的进程,再往下钻。三个必考概念:buffer/cache 是内核缓存可回收(free 命令显示的大不代表有问题)、available 才是真正可用内存、load average 高不一定内存问题(可能是 CPU 或 IO 等待)。
初级理解
free -h 输出逐列解读(面试必考):
- free 少 ≠ 内存不足:buff/cache 是内核用空闲内存缓存磁盘数据(读文件快),需要时立即回收给应用
- available 才是答案:估算"不触发 swap 的前提下还能给新进程多少内存"——判断内存是否紧张看它
- Swap used 高:说明物理内存真不够过,系统已经在拿磁盘当内存(性能雪崩),要警惕
top 必看行:第一行 load average(1/5/15 分钟平均负载),进程区按 Shift+M 按内存排序。RES 是进程实际占用的物理内存(排查看它,不是 VIRT)。
中级深入
load average 的正确理解:单位时间内可运行 + 不可中断睡眠(D 状态)的平均进程数。经验判断:load 持续 > CPU 核数说明排队了;但要结合 vmstat 1 区分是 CPU 忙(us/sy 高)还是 IO 等待(wa 高 → load 高但 CPU 空闲,去查磁盘)。
OOM(Out Of Memory)机制:物理内存+Swap 都耗尽时,内核的 oom_killer 按 oom_score 挑选进程杀掉。特征:进程"无故消失"、dmesg 里有 "Killed process" 记录。排查:
Java 进程特别说明(后端面试高频):JVM 的堆内存只占进程内存的一部分——堆外内存(DirectBuffer、Metaspace、线程栈、JIT 代码缓存、glibc malloc 碎片)都算在 RES 里。容器里"Xmx 设了 2G 但进程 RSS 4G 被杀"就是典型:堆外也要算预算,容器环境用 -XX:MaxRAMPercentage 并开启 NativeMemoryTracking 分析。
高级拓展
内存泄漏排查工具链:
- 趋势判断:监控 RES 随时间稳步上涨且不回落(GC 后也不降)→ 泄漏特征
- 进程内部分析:pmap -x <pid> 看内存段分布,找异常大的匿名段
- C/C++:valgrind(离线)/ jemalloc profiling(在线采样)
- Java:jmap -histo:live <pid> 看对象直方图;dump 后 MAT 分析支配树;NMT(NativeMemoryTracking=summary)看堆外
- 内核态:slabtop 看内核 slab 占用(dentry/inode 缓存泄漏会吃光内存)
Swap 的调优观点(体现经验):数据库类应用建议 swappiness=1(尽量不用 swap,IO 延迟不可控);通用应用 10~60。swap 高不等于要立即重启——先看是不是 buff/cache 回收压力,很多时候清缓存/限流即可恢复。
实战场景
场景一:告警"内存使用率 90%",标准排查流程
场景二:Java 服务容器里频繁被杀
场景三:系统卡但 CPU 不高
面试模拟
Q:free 命令里 free 很小、buff/cache 很大,需要处理吗?
A:看 available 列——它综合了可回收的 buff/cache,才是"真正可用"。Linux 设计就是"空闲内存拿来做缓存",free 小是正常状态。需要处理的情况只有:available 持续很低、swap 在涨、或某进程异常吃内存。手动 echo 3 > drop_caches 清缓存是面试雷点——生产上清了除了让下次读盘更慢没有任何收益。
Q:load average 10,CPU 使用率 5%,说明什么?
A:典型"load 高但 CPU 空闲"——load 里的贡献者大概率是不可中断 D 状态进程在等 IO。验证:vmstat 看 wa(IO 等待占比)和 b 列(D 状态数),ps -eo stat 找 D 进程;再用 iostat -x 看哪块盘 %util 打满。结论:不是 CPU 问题,是存储/IO 问题,按磁盘排查路径走。
Q:怎么区分"内存泄漏"和"内存正常增长"?
A:看趋势与可回收性。正常增长:随流量/缓存水位涨,有上限、GC 或到期淘汰后回落。泄漏:单调上涨不可逆(Java:Full GC 后 old 区基线持续抬升;C:RSS 永不释放)。做法是画 RES/堆使用率的长周期曲线 + 压测验证(恒定流量跑 24h,看是否收敛到平台期)。Java 再用 MAT 对比两个时点的 dump 找增长对象簇。