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 内存泄漏初步检测

内存泄漏怎么查?最土的办法就是定时采样。我曾经在一个网关项目里,就是靠这个办法抓到了泄漏点。

思路很简单:

  1. 每隔一段时间记录一次内存使用率
  2. 观察趋势是否持续上升
  3. 如果一直涨,不回落,大概率有泄漏

我写了个简单的监控脚本:

#!/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