如何通过Shell准确测量R语言多线程程序的内存使用情况?
问题:ps统计用户进程内存占比总和超100%,与free结果不符
背景
我用Shell脚本监控系统资源并发送告警,核心依赖以下命令统计指定用户的进程内存占比总和:
ps -u "$user" --no-headers -o pmem | awk '{sum += $1} END {print sum}'
多数场景下运行正常,但近期发现统计结果异常。
复现方式
在刚重启的干净系统中运行以下R代码,排除其他进程干扰:
library(data.table) library(parallel) set.seed(123) n_rows <- 1e7 n_cols <- 1000 # 内存占用较高,可根据自身系统调整,需达到可用内存的1/30至1/10以复现问题 dt <- data.table(matrix(runif(n_rows * n_cols), nrow = n_rows, ncol = n_cols)) memory_usage <- object.size(dt) format(memory_usage, units = "auto") worker_function <- function(data) { row_sums <- rowSums(data) # 休眠1000秒,方便运行Shell命令测试 Sys.sleep(1000) return(row_sums) } n_threads <- 10 results <- mclapply(1:n_threads, function(x) worker_function(dt), mc.cores = n_threads)
现象对比
- 执行以下命令统计用户进程内存占比总和,结果超过100%:
ps -u "$user" --no-headers -o pmem | awk '{sum += $1} END {print sum}' # 输出示例:113.9
- 用
free -h查看系统实际内存使用:
我的系统配置为1.5 TiB物理内存、2.0 GiB交换空间,free显示仅使用了645/1500 GiB,占比不足50%。
原因分析
ps的pmem字段统计的是进程包含共享内存在内的内存占比,当多个进程共享同一块内存(比如示例中R的mclapply创建的子进程共享父进程的dt数据)时,共享内存会被每个进程重复计算,导致总和超过100%。而free统计的是系统实际已使用的物理内存,共享内存仅被计算一次,因此两者结果存在差异。
解决方案
要准确统计用户实际占用的内存,需使用能处理共享内存重复计算的工具,比如smem:
smem -t -k -u -p -U "$user" | tail -1 | awk '{print $5}'
该命令会自动扣除共享内存的重复统计,结果更贴近系统实际内存占用情况。
内容的提问来源于stack exchange,提问作者zhang
相关产品推荐
相关产品推荐

