如何在Python中使用psutil获取程序的最大内存使用量
我正在使用以下代码来获取程序的最大内存使用量。
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)
2 个回答
这里的问题是,psutils会快速从/proc文件系统中获取一个快照,具体可以在源代码中看到。
当你运行你的“你好,世界”示例时,有时候它会在Python有机会从/proc读取值之前就结束了。
一旦这个进程结束,它实际上就不再占用任何内存了。你可以通过使用strace来确认这一点。
open("/proc/13420/statm", O_RDONLY) = 3
read(3, "0 0 0 0 0 0 0\n", 1024) = 14
如果你把示例修改为使用像sleep这样的命令,你会发现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命令,在大多数平台上,这个命令会给你启动的进程的平均总内存使用情况,或者像J.F Sebastian建议的那样使用valgrind……他在我研究和测试答案时也发了帖子;)
Hello World.. sleeping!0.00user 0.00system 0:03.00elapsed 0%CPU
(0avgtext+0avgdata 1144maxresident)k
0inputs+0outputs (0major+348minor)pagefaults 0swaps
<defunct>
表示这个子进程是一个僵尸进程(它已经结束了,但父进程还没有读取它的状态,通常是通过p.poll()
或p.wait()
来读取)。看起来无论是psutil
还是ps
都显示这类进程的RSS
(常驻内存集)为零。
结果取决于子进程是否会在调用p.memory_info()
之前就退出。这是一个竞争的过程。如果你在C++程序的退出时添加了延迟,那么p.memory_info()
可能会在子进程退出之前被调用,这样你就能得到非零的结果。
问题是我可以让任意程序进行评估。语言也不是固定的。难道没有优雅的解决方案吗?
你可能需要操作系统的支持,以便在子进程退出后仍然保存它的内存使用信息。或者你可以使用像valgrind
这样的内存分析工具来运行程序并读取它的结果。要收集结果:
$ valgrind --tool=massif cmd arg1 arg2
要查看结果,你可以使用ms_print
:
$ ms_print massif.out.* | less
或者使用图形界面的Massif-Visualizer
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 time使用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
报告的最大总内存:它们是相似的。
另请参见: