4. 内存瓶颈定位
内存问题,说实话,是实时系统里最难缠的对手。CPU 跑高了你能看到进程忙,IO 慢了你能看到磁盘在等,但内存泄漏——它就像温水煮青蛙,等你发现时,系统往往已经 OOM 了。
我个人习惯把内存排查分成三个层次:用量看趋势、分配看行为、泄漏看细节。这一章,我们就用 free、vmstat、smem 和 valgrind 这四把刀,一层层把内存问题剖开。
4.1 free:三秒判断内存水位
free 是我每次登服务器敲的第一个命令。别小看它,三行输出就能告诉你系统是不是在“硬撑”。
# 常用方式
free -h # 人类可读单位
free -s 2 -t # 每2秒刷新一次,显示总计
输出里我最关注的是 available 这一列。它才是真正可用的内存,不是 free 那列。为什么?因为 Linux 会把空闲内存拿去做 cache/buffer,但需要时能立刻回收。
4.2 vmstat:看内存变化的“心电图”
vmstat 能告诉你内存的变化趋势。我习惯让它持续跑,观察几轮数据。
vmstat 1 5
# 输出示例:
# procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
# r b swpd free buff cache si so bi bo in cs us sy id wa st
# 2 0 102400 345678 12345 678901 12 5 34 56 100 200 30 10 60 0 0
重点看两对指标:
- si / so(swap in / swap out):如果这两个值持续非零,说明系统正在频繁换页。这是性能杀手。
- free 列:持续下降且速度很快,说明有进程在“吃”内存。
我记得有一次线上告警,free 从 4G 掉到 200M 只用了 3 分钟。一看 si/so,每秒都在换页。那台机器的 Java 进程明显有泄漏。
4.3 smem:谁在“偷”你的内存?
smem 比 top 和 ps 更准确。它考虑了共享内存,能给出每个进程的 USS、PSS、RSS。
# 安装
apt install smem # 或 yum install smem
# 按物理内存使用排序
smem -r -k -s rss | head -20
# 只看某个用户
smem -u root -k
| 指标 | 含义 | 使用场景 |
|---|---|---|
| USS | 独占物理内存(不共享) | 判断进程真实内存占用 |
| PSS | 按比例分摊共享内存 | 系统级内存分配分析 |
| RSS | 全部驻留物理内存(含共享) | 快速看谁吃得多 |
我个人习惯用 PSS 做决策。RSS 会高估共享库的消耗,USS 又低估了。PSS 最接近真实情况。
4.4 valgrind:内存泄漏的“显微镜”
当怀疑某个进程有泄漏时,valgrind 是终极武器。它通过模拟 CPU 来检测每次内存分配和释放。
# 基本用法
valgrind --tool=memcheck --leak-check=full ./your_program
# 输出泄漏摘要
# ==12345== LEAK SUMMARY:
# ==12345== definitely lost: 1,024 bytes in 10 blocks
# ==12345== indirectly lost: 512 bytes in 5 blocks
# ==12345== possibly lost: 0 bytes in 0 blocks
# ==12345== still reachable: 0 bytes in 0 blocks
重点关注 definitely lost 和 indirectly lost。前者是直接泄漏,后者是因为指针丢失导致的级联泄漏。
/proc/pid/smaps 或 pmap 做初步判断就够了。
4.5 OOM 与 Swap:最后的防线
当内存耗尽,Linux 会启动 OOM Killer。它会根据 oom_score 杀掉一个进程。你想想看,如果被杀的是你的关键服务,那后果...
# 查看 OOM 日志
dmesg | grep -i oom
journalctl -k | grep -i oom
# 查看进程的 oom_score
cat /proc/<pid>/oom_score
Swap 是另一个“假救星”。很多人觉得开了 swap 就安全了,其实不然。当系统开始大量使用 swap,性能会断崖式下跌。因为磁盘 I/O 比内存慢几个数量级。
vm.swappiness=1。让 OOM 早点发生,比让系统在 swap 里“苟延残喘”要好。早死早超生,监控能及时告警。
4.6 实战排查流程
最后,我总结一个排查流程,你可以直接拿去用:
- 第一步:
free -h看 available 是否低于 10%。 - 第二步:
vmstat 1 5看 si/so 是否非零,free 是否持续下降。 - 第三步:
smem -r -k -s rss找出 TOP 10 内存消耗进程。 - 第四步: 对可疑进程用
pmap -x <pid>或cat /proc/<pid>/smaps看内存分布。 - 第五步: 测试环境用 valgrind 深挖泄漏点。
- 第六步: 检查 OOM 日志,确认是否有进程被误杀。
嗯,这套流程我用了很多年,基本没翻过车。内存问题不可怕,可怕的是没有排查思路。现在你有了。