You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux下如何获取进程树的整体峰值内存占用?

统计Linux进程树合并峰值内存占用的实现方案

你提到的resource.getrusage(RUSAGE_CHILDREN)确实无法满足需求——根据man手册,它仅返回单个子进程的最大驻留集大小(RSS),既不是进程树的瞬时总RSS峰值,也不是所有子进程峰值的总和。由于没有目标程序源码,只能通过定时采样进程树RSS总和的方式来获取合并峰值。


核心思路

  1. 启动目标程序后,获取其主进程PID
  2. 递归遍历该PID的所有后代进程(包括子进程的子进程)
  3. 定时采样所有进程的RSS值并累加,记录过程中的最大值
  4. 等待目标程序执行完毕后,输出最终的峰值内存占用

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 23:20:41