psutil 4.0.0 以及如何获得 Python 中 真正的 进程内存和环境
现在,psutil 4.0.0 已经出来了,它带来了关于进程内存度量的一些有趣的消息。我将开门见山说明有什么新东西。
真正的 进程内存信息
确定一个过程真的使用多少内存并不是一件容易的事(见 这个 和 这个 )。RSS(驻留集大小),这是大多数人平时靠的指标,它其实是会误导,因为它同时包含了进程独一无二的内存和与其他进程共享的内存。在分析方面更有趣的是,如果该进程即刻被终止,将释放的内存。在 Linux 的世界中,这被称为 USS(唯一集大小),并且这是在 psutil 4.0.0 引入(不仅适用于 Linux,也适用于 Windows 和 OSX)的主要功能。
USS 内存
USS(唯一集大小)是一个进程特有的内存,如果这个过程被终止,它将即刻被释放。在 Linux 上,这可以通过分析在 /proc/pid/smaps
中的所有“私有”块进行确定。Firefox 团队进一步对其进行推动,并且也成功地在 OSX 和 Windows 上做了同样的事。这是很棒的。psutil 新版本现在能够做同样的事:
>>> psutil.Process().memory_full_info()
pfullmem(rss=101990, vms=521888, shared=38804, text=28200, lib=0, data=59672, dirty=0,
uss=81623, pss=91788, swap=0)
PSS 和 swap
在 Linux 中,有两个也可以通过 /proc/pid/smaps
确定的额外指标:PSS 和 swap。PSS,又名“比例设置大小”,表示与其他进程共享的内存大小,它以这种方式进行计算: 总量最终在共享的进程之间平分 。也就是说,如果一个进程有 10 MB 都归自己(USS),并与另一个进程共享 10 MB,那么其 PSS 将是 15 MB。“swap”很简单,就是已经被交换到磁盘的内存量。使用 memory_full_info() 可以实现一个 像这样 的工具,类似于 Linux 上的 smem ,它提供了根据“USS”排序的进程列表。有趣的是,注意 RSS 和 USS 的区别:
~/svn/psutil$ ./scripts/procsmem.py
PID User Cmdline USS PSS Swap RSS
==============================================================================
...
3986 giampao /usr/bin/python3 /usr/bin/indi 15.3M 16.6M 0B 25.6M
3906 giampao /usr/lib/ibus/ibus-ui-gtk3 17.6M 18.1M 0B 26.7M
3991 giampao python /usr/bin/hp-systray -x 19.0M 23.3M 0B 40.7M
3830 giampao /usr/bin/ibus-daemon --daemoni 19.0M 19.0M 0B 21.4M
20529 giampao /opt/sublime_text/plugin_host 19.9M 20.1M 0B 22.0M
3990 giampao nautilus -n 20.6M 29.9M 0B 50.2M
3898 giampao /usr/lib/unity/unity-panel-ser 27.1M 27.9M 0B 37.7M
4176 giampao /usr/lib/evolution/evolution-c 35.7M 36.2M 0B 41.5M
20712 giampao /usr/bin/python -B /home/giamp 45.6M 45.9M 0B 49.4M
3880 giampao /usr/lib/x86_64-linux-gnu/hud/ 51.6M 52.7M 0B 61.3M
20513 giampao /opt/sublime_text/sublime_text 65.8M 73.0M 0B 87.9M
3976 giampao compiz 115.0M 117.0M 0B 130.9M
32486 giampao skype 145.1M 147.5M 0B 149.6M
实现
要获得这些值(USS, PSS 和 swap),我们需要遍历珍格格进程地址空间。这通常需要更高的用户权限,并且比通过 Process.memory_info() 获得“正常”的内存度量慢得多,这可能就是为什么像 ps
和 top
之类的工具显示 RSS/VMS 而不是 USS。非常感谢 Mozilla 团队,他们在 Windows 和 OSX 上都考虑到了这些,同时感谢 Eric Rahm,他为 psutil 把 PR 都放在一起了(见 #744 , #745 和 #746 )。对于你们那些不使用 Python,但是像将代码移植到另一个语言上的人,下面是有趣的部分:
内存类型百分比
经过 重组进程内存 API 后,我决定添加一个新的 memtype
参数到 Process.memory_percent() 中。与此,它现在可以将一个指定的内存类型(不仅仅是 RSS)与总物理内存进行比较了。例如:
>>> psutil.Process().memory_percent(memtype='pss')
0.06877466326787016
进程环境变量
psutil 4.0.0 中第二大改进是确定 进程环境变量 的能力。这将开启进程识别和监控技术的有趣的可能。例如,有人会通过传递某些自定义环境变量来启动一个进程,然后遍历所有进程来找到感兴趣的那个进程(并弄清楚它是否正在运行):
import psutil
for p in psutil.process_iter():
try:
env = p.environ()
except psutil.Error:
pass
else:
if 'MYAPP' in env:
...
进程环境变量是一个 长期存在的问题 , (在 2009 年) 因为 Windows 实现仅对当前进程有效,所以我放弃实现。Frank Benkstein 解决了这个问题 ,所以现在对于所有进程,都可以在 Linux, Windows 和 OSX 上确定进程变量(当然,你仍然可以碰到其他用户拥有的进程的 AccessDenied
):
>>> import psutil
>>> from pprint import pprint as pp
>>> pp(psutil.Process().environ())
{...
'CLUTTER_IM_MODULE': 'xim',
'COLORTERM': 'gnome-terminal',
'COMPIZ_BIN_PATH': '/usr/bin/',
'HOME': '/home/giampaolo',
'PWD': '/home/giampaolo/svn/psutil',
}
>>>
必须指出的是,所得到的字典通常不反映进程开始之后所做的更改(例如 os.environ['MYAPP'] = '1'
)。同样,对于任何有兴趣在其他语言中这样做的人,这里是有趣的部分:
扩展磁盘 IO 统计信息
psutil.disk_io_counters() 已经被扩展为报告 Linux 和 FreeBSD 上的附加度量:
busy_time
,这是进行实际 I/O 花费的时间(毫秒)。read_merged_count
和write_merged_count
(只用于 Linux),这是合并读数和合并写数(见 iostats 文档)
有了这些新的度量,就有可能有 实际磁盘利用率 的一个更好的表示,类似于 Linux 上的 iostat
命令。
OS 常量
Given the increasing number of platform-specific metrics I added a new set of 由于特定于平台的度量数量的增加,我添加了一套新的 常量 来快速区分你是在什么平台上: psutil.LINUX
, psutil.WINDOWS
等等。
主要 bug 修复
- #734 : 在 Python 3 上,对于 name() , cwd() , exe() , cmdline() 和 open_files() 方法,无效的 UTF-8 数据不能正确地被处理,从而导致
UnicodeDecodeError
。这影响到所有平台。现在 surrogateescape 错误处理成千被用作替换损坏的数据的解决方法。 - #761 : [Windows] psutil.boot_time() 在 49 天后不会再变成 0。
- #767 : [Linux] 在 2.6 内核上,disk_io_counters() 可能会引发 ValueError 错误,而在 2.4 内核上可能会崩溃。
- #764 : 现在可以在 NetBSD-6.X 上编译 psutil 了。
- #704 : 现在可以在 Solaris sparc 上编译 psutil 了。
完整的 bug 修复列表在 这里 。
移植代码
4.0.0 作为一个主要版本,我抓住机会(稍微的)修改/破坏某些 API。
- Process.memory_info() 不再只返回一个
(rss, vms)
命名元组。相反,它会返回一个可变长度,基于平台修改的命名元组(虽然rss
和vms
总是存在,在 Windows 上也是)。基本上,它返回与老的 process_memory_info_ex() 相同的结果。这不应该破坏你已有的代码,触发你正在使用"rss, vms = p.memory_info()"
。 - 同时, process_memory_info_ex() 现已启用。该方法作为 memory_info() 的别名仍然存在,它会发出一个弃用警告。
- psutil.disk_io_counters() 在 Linux 上返回两个额外的字段,在 FreeBSD 上返回一个额外的字段。
- NetBSD 和 OpenBSD 上的 psutil.disk_io_counters() 不再返回
write_count
和read_count
度量,因为内核不再提供它们(取而代之,我们返回忙绿时间)。我也不希望这是一个大问题,因为 OpenBSD 支持是非常近的。
最后说明,以及找工作
好了,就是这些了。(译者:后面是原文作者的一堆找工作的信息,有兴趣的请到原文上查看,这里就不进行翻译了)
外部链接
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

下一篇: Python 机器学习和语言之争
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论