【问题标题】:Python equivalent of PHP's memory_get_usage()?Python 相当于 PHP 的 memory_get_usage()?
【发布时间】:2010-10-28 05:31:47
【问题描述】:

我已经found the following question,但我想知道是否有一种更快更脏的方法来估计python解释器当前为我的脚本使用了多少内存,而不依赖于外部库。

我来自 PHP,过去经常为此使用 memory_get_usage()memory_get_peak_usage(),我希望能找到一个等价物。

【问题讨论】:

标签: python


【解决方案1】:

使用/proc/self/status 的Linux 和其他系统的简单解决方案是以下代码,我在我的一个项目中使用:

def memory_usage():
    """Memory usage of the current process in kilobytes."""
    status = None
    result = {'peak': 0, 'rss': 0}
    try:
        # This will only work on systems with a /proc file system
        # (like Linux).
        status = open('/proc/self/status')
        for line in status:
            parts = line.split()
            key = parts[0][2:-1].lower()
            if key in result:
                result[key] = int(parts[1])
    finally:
        if status is not None:
            status.close()
    return result

它返回当前和峰值驻留内存大小(这可能是人们谈论应用程序正在使用多少 RAM 时的意思)。很容易扩展它以从/proc/self/status 文件中获取其他信息。

对于好奇:cat /proc/self/status 的完整输出如下所示:

% cat /proc/self/status
Name:   cat
State:  R (running)
Tgid:   4145
Pid:    4145
PPid:   4103
TracerPid:      0
Uid:    1000    1000    1000    1000
Gid:    1000    1000    1000    1000
FDSize: 32
Groups: 20 24 25 29 40 44 46 100 1000 
VmPeak:     3580 kB
VmSize:     3580 kB
VmLck:         0 kB
VmHWM:       472 kB
VmRSS:       472 kB
VmData:      160 kB
VmStk:        84 kB
VmExe:        44 kB
VmLib:      1496 kB
VmPTE:        16 kB
Threads:        1
SigQ:   0/16382
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000000000
SigCgt: 0000000000000000
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: ffffffffffffffff
Cpus_allowed:   03
Cpus_allowed_list:      0-1
Mems_allowed:   1
Mems_allowed_list:      0
voluntary_ctxt_switches:        0
nonvoluntary_ctxt_switches:     0

【讨论】:

  • 是峰值/驻留 kb 还是字节?
  • 好问题 - 以千字节为单位,我已将该信息添加到原始答案中。
  • 非常感谢您的出色回答。顺便说一句,如果我产生一堆线程,即使居民保持相对较低,您是否知道为什么峰值最终会超过 80mb(!!!)?另外,您对如何在 Win32 上执行此操作有任何线索吗?
  • 不选择,但肯定是 Kilo (1000) 或 Kiki (1024) 字节?
【解决方案2】:

您也可以使用标准库模块resource 中的getrusage() 函数。结果对象具有属性ru_maxrss,它给出了调用进程的总峰值内存使用量:

>>> import resource
>>> resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
2656

Python docs 不清楚单位是什么,但Mac OS X man pagegetrusage(2) 将单位描述为千字节。

Linux 手册页不清楚,但它似乎等同于接受的答案中描述的/proc/self/status 信息(即千字节)。对于与上面相同的进程,在 Linux 上运行,接受的答案中列出的函数给出:

>>> memory_usage()                                    
{'peak': 6392, 'rss': 2656}

这可能不像/proc/self/status 解决方案那样容易使用,但它是标准库,因此(如果单元是标准的)它应该是跨平台的,并且可以在缺少/proc/ 的系统上使用(例如 Mac OS X 和其他 Unix,也许是 Windows)。

另外,getrusage() 函数也可以被赋予 resource.RUSAGE_CHILDREN 以获取子进程的使用情况,并且(在某些系统上)resource.RUSAGE_BOTH 用于总(自身和子)进程使用情况。

这将涵盖memory_get_usage() 的情况,但不包括峰值使用量。我不确定resource 模块中的任何其他功能是否可以提供峰值使用率。

【讨论】:

  • 我的 OSX (lion) 在我正在运行的进程上给出:35819520,我很确定是 35MB 而不是 35GB,所以它似乎是字节。 :)
  • 在我的 Ubuntu 11.10 机器上,我得到 resource.getrusage() 的值更接近 memory_usage() 的峰值而不是 rss。您确定 ru_maxrss 指的是当前内存使用量而不是峰值内存使用量吗?
  • @Phani 对我来说似乎也是使用高峰期。此答案中有关 ru_maxrss 的更多信息:stackoverflow.com/a/12050966/67184
  • 请注意,提供当前驻留集大小的 ru_idrss 字段当前未维护(Linux 3.10.7-2),因此它将返回 0。此 answer 有更多详细信息。
  • Mac OS 肯定以字节为单位返回 RSS,Linux 以千字节为单位返回。
【解决方案3】:

接受的答案规则,但使用psutil 可能更容易(并且更便携)。它的作用相同,而且更多。

更新:muppy 也非常方便(并且比 guppy/heapy 有更好的文档记录)。

【讨论】:

  • 你的答案是我接受的答案,但我不是问这个问题的人,所以我能给你的最好的就是一个赞成票。
  • 谢谢!我发现muppy 在某些方面甚至更好,并且记录得很好 - 如果您有内存泄漏问题,值得一试。
  • 具体见(几乎相同)答案:stackoverflow.com/a/21632554/1959808
【解决方案4】:

试试heapy

【讨论】:

    【解决方案5】:

    /proc/self/status 具有以下相关键:

    • VmPeak:峰值虚拟内存大小。
    • VmSize:虚拟内存大小。
    • VmHWM:峰值驻留集大小(“高水位线”)。
    • VmRSS:驻留集大小。

    因此,如果关注的是常驻内存,我可以使用以下代码来检索它:

    def get_proc_status(keys = None):
        with open('/proc/self/status') as f:
            data = dict(map(str.strip, line.split(':', 1)) for line in f)
    
        return tuple(data[k] for k in keys) if keys else data
    
    peak, current = get_proc_status(('VmHWM', 'VmRSS'))
    print(peak, current)  # outputs: 14280 kB 13696 kB
    

    这是一个article by memory_profiler's author,它解释了getrusageru_maxrss 并不总是一个实际的措施。另请注意,VmHWM 可能与ru_maxrss 不同(我在某些情况下看到的ru_maxrss 更大)。但在简单的情况下,它们是相同的:

    import resource
    
    
    def report():
        maxrss = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
        peak, current = get_proc_status(('VmHWM', 'VmRSS'))
        print(current, peak, maxrss)
    
    
    report()
    
    s = ' ' * 2 ** 28  # 256MiB
    report()
    
    s = None
    report()
    

    此外,这里有一个非常易于理解但内容丰富的case study by atop authors,它解释了什么是内核、虚拟内存和常驻内存,以及它们是如何相互依赖的。

    【讨论】:

      【解决方案6】:

      /proc/self/status 中的同类数据也在/proc/self/statm 中。但是,它更容易解析,因为它只是几个statistics 的空格分隔列表。我无法判断这两个文件是否始终存在。

      /proc/[pid]/statm

      提供有关内存使用情况的信息,以页为单位。 列是:

      • 大小 (1) 总程序大小 (与 /proc/[pid]/status 中的 VmSize 相同)
      • resident (2) 驻留集大小 (与 /proc/[pid]/status 中的 VmRSS 相同)
      • shared (3) 常驻共享页面的数量(即,由文件支持) (与 /proc/[pid]/status 中的 RssFile+RssShmem 相同)
      • 文字(4)文字(代码)
      • lib (5) 库(自 Linux 2.6 起未使用;始终为 0)
      • 数据 (6) 数据 + 堆栈
      • dt (7) 脏页(自 Linux 2.6 起未使用;始终为 0)

      这是一个简单的例子:

      from pathlib import Path
      from resource import getpagesize
      
      PAGESIZE = getpagesize()
      PATH = Path('/proc/self/statm')
      
      
      def get_resident_set_size() -> int:
          """Return the current resident set size in bytes."""
          # statm columns are: size resident shared text lib data dt
          statm = PATH.read_text()
          fields = statm.split()
          return int(fields[1]) * PAGESIZE
      
      
      data = []
      start_memory = get_resident_set_size()
      for _ in range(10):
          data.append('X' * 100000)
          print(get_resident_set_size() - start_memory)
      

      这会产生一个看起来像这样的列表:

      0
      0
      368640
      368640
      368640
      638976
      638976
      909312
      909312
      909312
      

      您可以看到它在大约 3 次分配 100,000 字节后跳跃了大约 300,000 字节。

      【讨论】:

        猜你喜欢
        • 2013-08-08
        • 2013-07-08
        • 1970-01-01
        • 1970-01-01
        • 2011-10-10
        • 1970-01-01
        • 2012-12-03
        • 1970-01-01
        • 2011-01-25
        相关资源
        最近更新 更多