4、内存监控实战:解析/proc/meminfo、脚本实现内存使用率计算与内存泄漏初步检测
4.1 为什么盯住内存不放?
嵌入式系统里,内存就是命根子。我见过太多项目,功能调通了,跑两天就挂了。一查,内存泄漏了。说白了,内存监控不是锦上添花,是保命手段。
你想想看,一个嵌入式设备可能连续跑几个月甚至几年。内存一点点漏,就像水管滴水,刚开始没事,时间长了墙就泡烂了。所以,我们必须学会怎么监控它。
4.2 /proc/meminfo 到底在说什么?
Linux 系统把内存信息都扔在 /proc/meminfo 里。这是个虚拟文件,内核实时生成的。我习惯用 cat /proc/meminfo 先看一眼,大概长这样:
MemTotal: 1024000 kB
MemFree: 512000 kB
MemAvailable: 614400 kB
Buffers: 10240 kB
Cached: 204800 kB
SwapTotal: 512000 kB
SwapFree: 409600 kB
这里有几个关键字段,我挑重要的说:
| 字段 | 含义 | 我的理解 |
|---|---|---|
| MemTotal | 物理内存总量 | 板子上焊了多少就是多少 |
| MemFree | 完全未使用的内存 | 这个值往往偏小,别被它吓到 |
| MemAvailable | 实际可用内存 | 这个才是你该看的,包含了可回收的缓存 |
| Buffers/Cached | 内核缓存和缓冲区 | 系统会尽量用空闲内存做缓存,这是好事 |
重点记住:别盯着 MemFree 看,要看 MemAvailable。MemAvailable 才是系统真正能分给你的内存。
4.3 手写一个内存使用率计算脚本
光看原始数据不够直观。我习惯写个脚本,直接算出使用率。嗯,这里要注意,计算方式有讲究。
我个人习惯用这个公式:
内存使用率 = (MemTotal - MemAvailable) / MemTotal * 100%
为什么不用 MemFree?因为 MemFree 不包括可回收的缓存。你用 MemFree 算,使用率会虚高,自己吓自己。
来看脚本:
#!/bin/bash
# 内存使用率计算脚本
# 我在项目中一直用这个,简单可靠
# 读取 /proc/meminfo
MEM_TOTAL=$(grep 'MemTotal' /proc/meminfo | awk '{print $2}')
MEM_AVAIL=$(grep 'MemAvailable' /proc/meminfo | awk '{print $2}')
# 计算使用率,保留两位小数
USAGE=$(echo "scale=2; ($MEM_TOTAL - $MEM_AVAIL) * 100 / $MEM_TOTAL" | bc)
echo "内存使用率: ${USAGE}%"
# 加个阈值告警
if (( $(echo "$USAGE > 90" | bc -l) )); then
echo "警告:内存使用率超过90%!"
fi
小技巧:我用 bc 做浮点运算,因为嵌入式系统的 shell 可能不支持直接浮点。如果你用 busybox,记得确认 bc 有没有编译进去。
4.4 内存泄漏初步检测
内存泄漏怎么查?最土的办法就是定时采样。我曾经在一个网关项目里,就是靠这个办法抓到了泄漏点。
思路很简单:
- 每隔一段时间记录一次内存使用率
- 观察趋势是否持续上升
- 如果一直涨,不回落,大概率有泄漏
我写了个简单的监控脚本:
#!/bin/bash
# 内存泄漏初步检测脚本
# 记录内存使用率到日志文件
LOG_FILE="/tmp/mem_monitor.log"
INTERVAL=60 # 每60秒采样一次
echo "开始监控内存,日志文件: $LOG_FILE"
echo "时间, 使用率(%)" > $LOG_FILE
while true; do
MEM_TOTAL=$(grep 'MemTotal' /proc/meminfo | awk '{print $2}')
MEM_AVAIL=$(grep 'MemAvailable' /proc/meminfo | awk '{print $2}')
USAGE=$(echo "scale=2; ($MEM_TOTAL - $MEM_AVAIL) * 100 / $MEM_TOTAL" | bc)
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
echo "$TIMESTAMP, $USAGE" >> $LOG_FILE
# 如果连续5次超过90%,发告警
# 这里简化处理,只打印
if (( $(echo "$USAGE > 90" | bc -l) )); then
echo "[$TIMESTAMP] 内存使用率异常: ${USAGE}%"
fi
sleep $INTERVAL
done
注意:这个脚本只是初步检测。它只能告诉你「可能泄漏了」,不能告诉你「哪里泄漏了」。真要定位泄漏点,还得上 valgrind 或者 AddressSanitizer。我在项目中吃过这个亏,脚本报警了,但找泄漏点找了三天。
4.5 实战中的避坑指南
做内存监控这几年,我踩过不少坑。挑几个典型的说说:
- 别只看瞬时值。 内存使用率有波动是正常的。我习惯看5分钟内的平均值,或者看趋势线。
- 注意缓存的影响。 系统刚启动时,缓存还没建立,MemAvailable 可能偏低。跑一会儿就正常了。
- Swap 也要看。 如果 Swap 使用率在涨,说明物理内存真的不够了。我曾经遇到过,内存使用率才70%,但 Swap 已经用了一半,系统慢得像蜗牛。
我的经验:嵌入式设备的内存泄漏,80% 出在动态分配没释放上。malloc 了忘记 free,或者 open 了文件描述符忘记 close。写代码时养成好习惯,比事后排查省心一百倍。
4.6 小结
这一章我们干了三件事:
- 读懂了 /proc/meminfo 里的关键字段
- 写了个靠谱的内存使用率计算脚本
- 搭了个内存泄漏初步检测框架
说白了,监控是第一步,优化是第二步。下一章我们会聊怎么用这些数据做内存优化。嗯,到时候再细说。
公众号:蓝海资料掘金营,微信deep3321