【问题标题】:How to get the max memory usage of a program using psutil in Python如何在 Python 中使用 psutil 获取程序的最大内存使用量
【发布时间】:2014-05-09 02:26:01
【问题描述】:

我正在使用以下代码来获取程序的最大内存使用量。

    import os, subprocess , psutil
    def mem(cmd):
        try:
            with open('in.txt','r') as infile, open('out.txt', 'w') as outfile:
                p=psutil.Popen("./"+cmd,shell=False,stdin=infile,stdout = outfile)
            print p.memory_info()
        except Exception:
             print "Error"
    cmd=raw_input()
    mem(cmd)

问题有时是程序的初始运行,内存使用输出为 (0,0),但随后它显示正确的输出。我不知道为什么会这样。对于某些程序,例如 c++ 中的 hello world 程序,输出为pmem(rss=4096, vms=315392),大约为 0.3M(我认为输出以字节为单位),但在 ideone.com 中运行 hello world 程序给出的输出为 ~3M。为什么会有这种分散性?

cmd 是可执行文件的名称。

命令print subprocess.check_output(['ps', 'v', '-p', str(p.pid)])的输出

PID TTY STAT TIME MAJFL TRS DRS RSS %MEM COMMAND 16150 pts/16 Z+ 0:00 0 0 0 0 0.0 [a.out] <defunct>

我的一个示例 C++ 程序:

`int a[1000000];
int main()
{
    return 0;
}`

有时返回 pmem(rss=4096, vms=4313088) 有时返回 pmem(rss=0,vms=0)

【问题讨论】:

  • 你能用["python", "-c", "pass"]这样的已知程序重现它吗?您确定没有抑制异常,即Popen() 成功启动?
  • 不相关:如果是stderr=PIPE,那么您应该从p.stderr 读取,否则如果它在stderr 上生成足够的输出来填充相应的操作系统管道缓冲区,则该进程可能会永远阻塞。
  • @J.F.Sebastian 删除了标准错误。
  • print subprocess.check_output(['ps', 'v', '-p', str(p.pid)]) 显示什么?
  • @J.F.Sebastian 我添加了异常处理。有时输出是(0,0),也不例外

标签: python unix python-2.7 memory


【解决方案1】:

这里的问题是 psutils 从 /proc 文件系统获取快速快照,您可以在 source 中看到。

当您运行 hello world 示例时,在某些情况下,它会在 python 有机会从 /proc 读取值之前完成。

一旦进程完成,它实际上不再消耗任何内存。您可以通过 strace 确认这一点。

open("/proc/13420/statm", O_RDONLY)     = 3
read(3, "0 0 0 0 0 0 0\n", 1024)        = 14

如果您修改示例以使用睡眠之类的东西,您会注意到 psutils 始终如一地返回内存使用量。

#include <iostream>
#include <unistd.h>

int main()
{
  std::cout << "Hello World.. sleeping!";
  sleep(3);
}

python 脚本的输出...

a.out
meminfo(rss=286720, vms=12931072)

完成您想要做的事情的一种简单方法是使用 /usr/bin/time 命令,在大多数平台上,该命令将为您提供您启动的进程的平均总内存使用量,或者使用 valgrind 作为 JF Sebastian建议...谁在我研究和测试我的答案时发布;)

Hello World.. sleeping!0.00user 0.00system 0:03.00elapsed 0%CPU     
(0avgtext+0avgdata 1144maxresident)k
0inputs+0outputs (0major+348minor)pagefaults 0swaps

【讨论】:

  • /usr/bin/time -f %M &lt;command&gt; 将打印“进程在其生命周期内的最大驻留集大小,以千字节为单位”
  • 为什么我运行程序时 rss 大小这么低。对于实际内存使用量约为 49MB 的程序,我的最大 rss 大小为 3292KB?我的系统有问题吗?
【解决方案2】:

&lt;defunct&gt; 表示子进程是zombie process(它已死,但父进程尚未读取其状态(p.poll()p.wait()))。对于此类进程,psutilps 似乎都显示 RSS 为零。

结果取决于子进程是否会在p.memory_info() 被调用之前退出。这是一场比赛。如果您在 C++ 程序的退出处添加延迟,则可能会在子进程退出之前调用 p.memory_info(),您应该会得到非零结果。

问题是我可以得到任意程序来评估 .语言也不固定。这个问题没有优雅的解决方案吗?

即使在子进程退出后,您也可能需要操作系统支持来保存有关子进程的内存使用情况的信息。或者您可以使用诸如valgrind 之类的内存分析器运行程序并读取其结果。收集结果:

$ valgrind --tool=massif cmd arg1 arg2 

要查看结果,您可以使用ms_print:

$ ms_print massif.out.* | less

或图形界面Massif-Visualizer

@mdadm suggested 更简单的解决方案:time command

from subprocess import Popen, PIPE

p = Popen(['time', '-f', '%M'] + args, stderr=PIPE)
ru_maxrss = int(p.communicate()[1])
print("Maximum rss %d KB" % ru_maxrss)

GNU 时间使用wait3() 来填充可用的资源使用信息。可以在 Python 中调用:

import os
from subprocess import Popen

p = Popen(args)
ru = os.wait4(p.pid, 0)[2]
print("Maximum rss %d KB" % ru.ru_maxrss)

我将psutil.Process.memory_info (rss) 返回的最大值与os.wait4 返回的ru_maxrss 值以及valgrind --tool=massif 报告的最大总内存进行了比较:它们相似 .

另见:

【讨论】:

  • 但我得到了一个 即使当 pmem(rss=4096, vms=4313088)... 是由于竞争条件,因为我把打印语句放在 p.memory_info() 之后跨度>
  • 子进程可能在您调用ps 时已经死亡,但在p.memory_info() 期间它仍然存在
  • 问题是我可以得到任意程序来评估。语言也不固定。这个问题没有优雅的解决方案吗
  • 我尝试使用/usr/bin/time -v ./a.out&lt;int.txt&gt;out.txt,但驻留集大小仍然不准确,非常低
  • 我添加了基于os.wait4() 的解决方案。它类似于您原来的基于resource 的解决方案。您是否将它们与psutilvalgrind 结果进行比较?
猜你喜欢
  • 2017-08-12
  • 2021-07-03
  • 1970-01-01
  • 2012-02-26
  • 2018-02-23
  • 2012-12-11
  • 2012-04-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多