让busybox里的free命令可以显示page cache

busybox的free命令不能显示page cache,导致于其功能大打折扣,因为page cache大小很大,在用户申请内存时可以回收,打上如下补丁后,busybox的free命令变得完整:

commit 2219fd301a7f319258ad4be9217cd0d6db9240d4 Author: Barry Song <Baohua.Song@xxx.xxx> Date: Mon Mar 26 11:47:10 2012 +0800 busybox: update free command to include page cache eg. sh-4.2$ free total used free shared buffers cached Mem: 402924 49232 353692 0 668 32160 -/+ buffers/cache: 16404 386520 Swap: 0 0 0 Change-Id: Ic9de9f8cd0051da8fd61ae8238a1d2573587223b Signed-off-by: Barry Song <Baohua.Song@xxx.xxx> diff --git a/procps/free.c b/procps/free.c index efbac5b..6abf1e8 100644 --- a/procps/free.c +++ b/procps/free.c @@ -29,11 +29,35 @@ static unsigned long long scale(unsigned long d) return ((unsigned long long)d * G.mem_unit) >> G_unit_steps; } +static unsigned long get_cache_from_meminfo(void) +{ +#define LINE_LEN 256 + FILE *fp; + char str[LINE_LEN]; + unsigned long long cached; + if((fp = fopen("/proc/meminfo","rt")) == NULL) { + printf("Cantnot open /proc/meminfo"); + exit(1); + } + + while(1) { + fgets(str, LINE_LEN, fp); + if (!strncmp(str, "Cached:", strlen("Cached:"))) + break; + } + + cached = atoi(str + strlen("Cached:")); + + fclose(fp); + + return cached; +} int free_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int free_main(int argc UNUSED_PARAM, char **argv IF_NOT_DESKTOP(UNUSED_PARAM)) { struct sysinfo info; + unsigned long long cached; INIT_G(); @@ -60,43 +84,45 @@ int free_main(int argc UNUSED_PARAM, char **argv IF_NOT_DESKTOP(UNUSED_PARAM)) #endif sysinfo(&info); + cached = get_cache_from_meminfo(); /* Kernels prior to 2.4.x will return info.mem_unit==0, so cope... */ G.mem_unit = (info.mem_unit ? info.mem_unit : 1); - printf(" %13s%13s%13s%13s%13s\n", + printf(" %13s%13s%13s%13s%13s%13s\n", "total", "used", "free", - "shared", "buffers" /* swap and total don't have these columns */ + "shared", "buffers", "cached" /* swap and total don't have these columns */ /* procps version 3.2.8 also shows "cached" column, but * sysinfo() does not provide this value, need to parse * /proc/meminfo instead and get "Cached: NNN kB" from there. */ ); -#define FIELDS_5 "%13llu%13llu%13llu%13llu%13llu\n" -#define FIELDS_3 (FIELDS_5 + 2*6) -#define FIELDS_2 (FIELDS_5 + 3*6) +#define FIELDS_6 "%13llu%13llu%13llu%13llu%13llu%13llu\n" +#define FIELDS_3 (FIELDS_6 + 3*6) +#define FIELDS_2 (FIELDS_6 + 4*6) - printf("Mem: "); - printf(FIELDS_5, + printf("Mem: "); + printf(FIELDS_6, scale(info.totalram), scale(info.totalram - info.freeram), scale(info.freeram), scale(info.sharedram), - scale(info.bufferram) + scale(info.bufferram), + cached ); /* Show alternate, more meaningful busy/free numbers by counting * buffer cache as free memory (make it "-/+ buffers/cache" * if/when we add support for "cached" column): */ - printf("-/+ buffers: "); + printf("-/+ buffers/cache: "); printf(FIELDS_2, - scale(info.totalram - info.freeram - info.bufferram), - scale(info.freeram + info.bufferram) + scale(info.totalram - info.freeram - info.bufferram) - cached, + scale(info.freeram + info.bufferram) + cached ); #if BB_MMU - printf("Swap:"); + printf("Swap: "); printf(FIELDS_3, scale(info.totalswap), scale(info.totalswap - info.freeswap),


你提供的日志内容如下: ``` 11:30:17 | PID:2649 VSZ:root KB %MEM:617m | Free: 1007432MB Time | PID VSZ(KB) %MEM | Free 11:30:19 | PID:2649 VSZ:root KB %MEM:617m | Free: 1007488MB 11:31:09 | PID:2649 VSZ:root KB %MEM:617m | Free: 1007700MB 11:32:00 | PID:2649 VSZ:root KB %MEM:617m | Free: 1008152MB 11:32:50 | PID:2649 VSZ:root KB %MEM:617m | Free: 1008336MB 11:33:41 | PID:2649 VSZ:root KB %MEM:617m | Free: 1006628MB ``` 这个输出 **看起来有问题**,尤其是 `VSZ:root KB` 和 `%MEM:617m` 这种格式明显是 **解析错误导致的乱码或字段错位**。 我们来逐项分析含义、问题原因,并告诉你 **如何修复脚本以获得正确数据**。 --- ## 🔍 一、各字段本应代表什么? | 字段 | 正确含义 | |------|--------| | `11:30:17` | 时间戳(HH:MM:SS) | | `PID:2649` | 目标进程 ID 是 2649 | | `VSZ` | Virtual Size —— 虚拟内存大小(单位 KB) | | `%MEM` | 该进程占用物理内存的百分比(如 1.5%) | | `Free: ... MB` | 系统当前空闲物理内存(来自 `free -m`) | ✅ 正常应该像这样: ``` 11:30:17 | PID:2649 VSZ:45600 KB %MEM:1.2 | Free: 890MB ``` 但你的输出却是: ``` VSZ:root KB %MEM:617m ``` 这说明:**ps 命令输出被误解析了!** --- ## ❌ 二、问题出在哪?—— `ps w` 输出格式混乱 你在使用 BusyBox 的 `ps w` 命令时,它的输出可能长这样: ```text PID VSZ %MEM COMMAND 2649 617m root /usr/bin/nvrcore ``` 注意这的关键点: - 第二列是数字,而是 `617m`(表示 617MB?但它是字符串) - 第三列是 `root`(用户名),是 `%MEM` - 第四列开始才是命令 也就是说:**`VSZ` 列出现了非数字字符 `m`,而 `%MEM` 实际上根本没显示!** 这是某些嵌入式系统中 `ps` 的特殊行为:当内存超过一定值后,用 `K/M/G/m/g` 表示单位(例如 `617m` = 617MB),但这会导致脚本解析失败。 --- ## 🧩 三、具体分析你这条日志 ``` 11:30:17 | PID:2649 VSZ:root KB %MEM:617m | Free: 1007432MB ``` 拆解一下你的脚本逻辑中的变量提取: ```sh ps_out=$(ps w | grep "^ *$PID ") # 示例输出: " 2649 617m root /usr/bin/nvrcore" pid=$(echo "$ps_out" | awk '{print $1}') → 2649 ✅ vsz=$(echo "$ps_out" | awk '{print $2}') → 617m ❌(带单位字母) mem_percent=$(echo "$ps_out" | awk '{print $3}') → root ❌(这是 %MEM!) ``` 所以你把: - `vsz=617m` 当成了虚拟内存 → 显示为 `"VSZ:root KB"`?可能是后续替换错误 - `%MEM=root` → 错误地显示为 `%MEM:617m` 这就完全 **颠倒了字段顺序**! > 💥 结论:你的 `ps` 输出格式和标准一样,导致脚本解析错位! --- ## ✅ 四、解决方案:改进 `log_memory()` 函数 我们需要一个更健壮的方式来获取进程内存信息。 ### ✔️ 推荐方法:从 `/proc/$PID/status` 文件读取 `VmSize` 和 `VmRSS` Linux 内核会在 `/proc/[pid]/status` 中提供精确的内存信息,受 `ps` 格式限制。 --- ### ✅ 修改后的 `log_memory()` 函数(兼容性强) ```sh log_memory() { local time=$(date '+%H:%M:%S') # 检查进程是否存在 if ! kill -0 $PID 2>/dev/null; then echo "$time | Error: Process $PID no longer exists!" >> "$LOG_FILE" return fi # 从 /proc/PID/status 读取内存信息(单位:kB) local vm_size="N/A" local vm_rss="N/A" local mem_line=$(grep "^VmSize:" /proc/$PID/status 2>/dev/null) local rss_line=$(grep "^VmRSS:" /proc/$PID/status 2>/dev/null) vm_size=$(echo "$mem_line" | awk '{print $2}') # 单位 kB vm_rss=$(echo "$rss_line" | awk '{print $2}') # 单位 kB # 获取系统空闲内存(MB) local free_mem=$(free -m | awk '/^Mem:/ {print $4}') # 写入日志 echo "$time | PID:$PID VMSZ:${vm_size}kB RSS:${vm_rss}kB | Free: ${free_mem}MB" >> "$LOG_FILE" } ``` --- ### ✅ 替换原脚本中的 `log_memory` 函数即可 #### ✅ 优点: - 依赖 `ps` 命令格式 - 数据准确(直接来自内核) - 兼容 BusyBox、OpenWrt、各种裁剪系统 - `VmRSS` 就是真实使用的物理内存(比 `free` 更精准看单个进程) --- ### ✅ 正确的日志输出示例 ``` 11:30:17 | PID:2649 VMSZ:45600kB RSS:32100kB | Free: 890MB 11:30:19 | PID:2649 VMSZ:45700kB RSS:32200kB | Free: 885MB ... ``` 你现在可以清晰看到: - `RSS` 是否持续增长 → 可能有内存泄漏 - `Free` 是否下降后恢复 → 缓存未释放 or 泄漏 --- ## 📊 五、解读你目前的数据(尽管有误) 虽然字段错乱,但我们仍能看出一些趋势: | 时间 | Free 内存(MB) | |------------|------------------| | 11:30:17 | 1,007,432 | | 11:30:19 | 1,007,488 (+56) | | 11:31:09 | 1,007,700 (+212) | | 11:32:00 | 1,008,152 (+452) | | 11:32:50 | 1,008,336 (+184) | | 11:33:41 | 1,006,628 (-1708)| 👉 观察: - 前面几分钟:空闲内存 **在上升**?太合理 - 最后一次突然掉到 `1006628`,下降了近 2GB? ⚠️ 这极有可能是因为: - 系统开启了缓存机制(如 page cache) - 或其他后台任务干扰(日志轮转、网络上传等) - 或 `free` 单位其实是 KB?但你说是 MB... > ❗请确认 `free -m` 输出是否真的是 MB。有些嵌入式系统 `free` 没参数支持,只输出 KB。 你可以手动运行验证: ```bash free -m # 如果报错,试试 free -k # KB free # 默认可能是 KB ``` --- ## ✅ 总结 | 问题 | 原因 | 解决方案 | |------|------|----------| | `VSZ:root KB %MEM:617m` | `ps` 输出格式异常,字段解析错位 | 改用 `/proc/$PID/status` 读取内存 | | 数据合理波动 | `free` 单位明、缓存干扰 | 使用 `free -m` 确认单位,关注 `RSS` 趋势 | | 无法判断内存泄漏 | 当前数据可信 | 用新脚本重新跑测试 | --- ## ✅ 下一步建议 1. **替换 `log_memory()` 函数** 2. **重新运行测试** 3. **查看新的日志中 `RSS` 是否稳定** 如果 `RSS` 随着插入操作持续上升且回落 → 存在内存泄漏 如果 `RSS` 上升后下降 → 正常释放 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值