Linux下如何获取进程树的整体峰值内存占用?
统计Linux进程树合并峰值内存占用的实现方案
你提到的resource.getrusage(RUSAGE_CHILDREN)确实无法满足需求——根据man手册,它仅返回单个子进程的最大驻留集大小(RSS),既不是进程树的瞬时总RSS峰值,也不是所有子进程峰值的总和。由于没有目标程序源码,只能通过定时采样进程树RSS总和的方式来获取合并峰值。
核心思路
- 启动目标程序后,获取其主进程PID
- 递归遍历该PID的所有后代进程(包括子进程的子进程)
- 定时采样所有进程的RSS值并累加,记录过程中的最大值
- 等待目标程序执行完毕后,输出最终的峰值内存占用
Python代码实现(推荐用psutil简化操作)
import os import sys import time import subprocess import psutil # 未安装可执行:pip install psutil def get_process_tree_rss_sum(pid): """递归计算指定PID及其所有子进程的总RSS(单位:KB)""" total_rss = 0 try: proc = psutil.Process(pid) # 转换为KB(psutil默认返回字节) total_rss += proc.memory_info().rss // 1024 # 递归处理所有后代进程 for child in proc.children(recursive=True): total_rss += child.memory_info().rss // 1024 except (psutil.NoSuchProcess, psutil.AccessDenied): # 进程已退出或无权限访问,直接跳过 pass return total_rss def run_and_track_memory(cmd, sample_interval=0.1): """运行命令并跟踪其进程树的峰值内存占用""" proc = subprocess.Popen(cmd, shell=True) peak_rss = 0 try: # 程序运行期间持续采样 while proc.poll() is None: current_sum = get_process_tree_rss_sum(proc.pid) if current_sum > peak_rss: peak_rss = current_sum time.sleep(sample_interval) # 程序结束后再采样一次,避免错过最后峰值 final_sum = get_process_tree_rss_sum(proc.pid) peak_rss = max(peak_rss, final_sum) finally: # 确保异常情况下子进程被清理 try: proc.terminate() proc.wait(timeout=5) except subprocess.TimeoutExpired: proc.kill() return peak_rss if __name__ == "__main__": if len(sys.argv) < 2: print("用法: python track_memory.py <目标命令>") sys.exit(1) cmd = " ".join(sys.argv[1:]) peak = run_and_track_memory(cmd) print(f"进程树合并峰值内存占用: {peak} KB")
替代方案(无需psutil,手动解析/proc)
如果无法安装第三方库,可通过读取/proc文件系统实现:
def get_child_pids(parent_pid): """手动递归获取指定PID的所有子进程PID""" child_pids = [] for pid_dir in os.listdir("/proc"): if not pid_dir.isdigit(): continue pid = int(pid_dir) try: with open(f"/proc/{pid}/status", "r") as f: for line in f: if line.startswith("PPid:"): ppid = int(line.split()[1]) if ppid == parent_pid: child_pids.append(pid) child_pids.extend(get_child_pids(pid)) break except (FileNotFoundError, PermissionError): continue return child_pids def get_process_rss(pid): """获取单个进程的RSS(单位:KB)""" try: with open(f"/proc/{pid}/statm", "r") as f: pages = int(f.readline().split()[0]) page_size = os.sysconf("SC_PAGESIZE") // 1024 # 转换为KB return pages * page_size except (FileNotFoundError, PermissionError): return 0 def get_process_tree_rss_sum(pid): total = get_process_rss(pid) for child_pid in get_child_pids(pid): total += get_process_rss(child_pid) return total
将上述函数替换到之前的代码中即可使用。
注意事项
- 采样间隔:默认0.1秒,可按需调整——间隔越小精度越高,但CPU占用也会增加
- 权限要求:需要有读取目标进程
/proc目录的权限 - 异常处理:采样时需处理进程已退出或无权限访问的情况
- 单位转换:代码返回单位为KB,若需MB可除以1024
内容的提问来源于stack exchange,提问作者Alex I
相关产品推荐
相关产品推荐

