【问题标题】:Total memory used by Python process?Python进程使用的总内存?
【发布时间】:2019-06-26 21:58:32
【问题描述】:

有没有办法让 Python 程序确定它当前使用了多少内存?我已经看到有关单个对象的内存使用情况的讨论,但我需要的是进程的总内存使用情况,以便我可以确定何时需要开始丢弃缓存的数据。

【问题讨论】:

    标签: python memory-management


    【解决方案1】:

    在 Windows 上,您可以使用 WMI(home pagecheeseshop):

    def memory():
        import os
        from wmi import WMI
        w = WMI('.')
        result = w.query("SELECT WorkingSet FROM Win32_PerfRawData_PerfProc_Process WHERE IDProcess=%d" % os.getpid())
        return int(result[0].WorkingSet)
    

    在 Linux 上(来自 python 食谱http://code.activestate.com/recipes/286222/

    import os
    _proc_status = '/proc/%d/status' % os.getpid()
    
    _scale = {'kB': 1024.0, 'mB': 1024.0*1024.0, 'KB': 1024.0, 'MB': 1024.0*1024.0}
    
    def _VmB(VmKey):
        '''Private.'''
        global _proc_status, _scale
         # get pseudo file  /proc/<pid>/status
        try:
            t = open(_proc_status)
            v = t.read()
            t.close()
        except:
            return 0.0  # non-Linux?
         # get VmKey line e.g. 'VmRSS:  9999  kB\n ...'
        i = v.index(VmKey)
        v = v[i:].split(None, 3)  # whitespace
        if len(v) < 3:
            return 0.0  # invalid format?
         # convert Vm value to bytes
        return float(v[1]) * _scale[v[2]]
    
    def memory(since=0.0):
        '''Return memory usage in bytes.'''
        return _VmB('VmSize:') - since
    
    def resident(since=0.0):
        '''Return resident memory usage in bytes.'''
        return _VmB('VmRSS:') - since
    
    def stacksize(since=0.0):
        '''Return stack size in bytes.'''
        return _VmB('VmStk:') - since
    

    【讨论】:

    • Windows 代码对我不起作用。此更改确实:return int(result[0].WorkingSet)
    • 这个 Windows 代码在 Windows 7 x64 上对我不起作用,即使在 John Fouhy 的评论修改之后。
    • 我有这个错误:返回 [wmi_object (obj, instance_of, fields) for obj in self._raw_query(wql)] 文件 "C:\Python27\lib\site-packages\win32com \client\util.py",第 84 行,在下一个 return _get_good_object_(self._iter.next(), resultCLSID = self.resultCLSID) pywintypes.com_error: (-2147217385, 'OLE error 0x80041017', None,无)是否有人可以帮助我?我赢了 8 x64 但 x32 上的 python
    • 注意:在检查了 wmi 模块的(最新)源代码后,我按照 John Fouhy 的建议更新了 windows 示例。另见(1)(2)
    • @jedwards:在 >90% 的情况下,WorkingSet 是一个非常糟糕的数字。它只是当前在 RAM 中的那部分内存
    【解决方案2】:

    Here 是一个有用的解决方案,适用于各种操作系统,包括 Linux、Windows 等:

    import os, psutil
    process = psutil.Process(os.getpid())
    print(process.memory_info().rss)  # in bytes 
    

    对于 Python 2.7 和 psutil 5.6.3,最后一行应该是

    print(process.memory_info()[0])
    

    改为(后来 API 发生了变化)。

    注意:

    • 如果尚未安装,请执行pip install psutil

    • 如果您想快速知道您的进程占用了多少 MB,则可以使用方便的单线:

      import os, psutil; print(psutil.Process(os.getpid()).memory_info().rss / 1024 ** 2)
      

    【讨论】:

    • psutil 是跨平台的,可以返回与ps 命令行工具相同的值:pythonhosted.org/psutil/#psutil.Process.memory_info
    • 为什么这个数字与进程浏览器中的不匹配? psutil 中的数字似乎总是大 10% 左右。
    • 注意psutil不在标准库中
    • 对于psutil 的最新版本,psutil.Process() 等同于psutil.Process(os.getpid())。这是您需要记住的少一件事。
    • 你为什么使用 rss?在 psutil 文档中:rss |驻留集大小,vms |总程序大小。所以我认为最后一行应该是print(process.memory_info().vms)
    【解决方案3】:

    当前进程的当前内存使用情况Linux,适用于 Python 2、Python 3pypy , 没有任何导入:

    def getCurrentMemoryUsage():
        ''' Memory usage in kB '''
    
        with open('/proc/self/status') as f:
            memusage = f.read().split('VmRSS:')[1].split('\n')[0][:-3]
    
        return int(memusage.strip())
    

    它读取当前进程的状态文件,取VmRSS:之后的所有内容,然后取第一个换行符之前的所有内容(隔离VmRSS的值),最后切断最后3个字节,即空格和单位(kB)。
    要返回,它会删除所有空格并将其作为数字返回。

    在 Linux 4.4 和 4.9 上测试,但即使是早期的 Linux 版本也应该可以工作:查看 man proc 并搜索 /proc/$PID/status 文件中的信息,它提到了某些字段的最低版本(如 Linux 2.6.10 for “VmPTE”),但“VmRSS”字段(我在这里使用)没有这样的提及。因此,我认为它从早期版本就已经存在。

    【讨论】:

      【解决方案4】:

      对于 Unix 系统,命令 time (/usr/bin/time) 如果您传递 -v,则会为您提供该信息。请参阅下面的Maximum resident set size,这是最大(峰值)真实(非虚拟)程序执行期间使用的内存

      $ /usr/bin/time -v ls /
      
          Command being timed: "ls /"
          User time (seconds): 0.00
          System time (seconds): 0.01
          Percent of CPU this job got: 250%
          Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.00
          Average shared text size (kbytes): 0
          Average unshared data size (kbytes): 0
          Average stack size (kbytes): 0
          Average total size (kbytes): 0
          Maximum resident set size (kbytes): 0
          Average resident set size (kbytes): 0
          Major (requiring I/O) page faults: 0
          Minor (reclaiming a frame) page faults: 315
          Voluntary context switches: 2
          Involuntary context switches: 0
          Swaps: 0
          File system inputs: 0
          File system outputs: 0
          Socket messages sent: 0
          Socket messages received: 0
          Signals delivered: 0
          Page size (bytes): 4096
          Exit status: 0
      

      【讨论】:

      【解决方案5】:

      下面是我的函数装饰器,它允许跟踪这个进程在函数调用之前消耗了多少内存,在函数调用之后它使用了多少内存,以及函数执行了多长时间。

      import time
      import os
      import psutil
      
      
      def elapsed_since(start):
          return time.strftime("%H:%M:%S", time.gmtime(time.time() - start))
      
      
      def get_process_memory():
          process = psutil.Process(os.getpid())
          return process.memory_info().rss
      
      
      def track(func):
          def wrapper(*args, **kwargs):
              mem_before = get_process_memory()
              start = time.time()
              result = func(*args, **kwargs)
              elapsed_time = elapsed_since(start)
              mem_after = get_process_memory()
              print("{}: memory before: {:,}, after: {:,}, consumed: {:,}; exec time: {}".format(
                  func.__name__,
                  mem_before, mem_after, mem_after - mem_before,
                  elapsed_time))
              return result
          return wrapper
      

      所以,当你有一些用它装饰的函数时

      from utils import track
      
      @track
      def list_create(n):
          print("inside list create")
          return [1] * n
      

      您将能够看到以下输出:

      inside list create
      list_create: memory before: 45,928,448, after: 46,211,072, consumed: 282,624; exec time: 00:00:00
      

      【讨论】:

        【解决方案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 字节。

        【讨论】:

          【解决方案7】:

          对于基于 Unix 的系统(Linux、Mac OS X、Solaris),您可以使用标准库模块resource 中的getrusage() 函数。结果对象具有属性ru_maxrss,它给出了调用进程的峰值内存使用量:

          >>> resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
          2656  # peak memory usage (kilobytes on Linux, bytes on OS X)
          

          Python docs 不记录单位。请参阅特定系统的man getrusage.2 页面以检查单位的值。在 Ubuntu 18.04 上,单位以千字节表示。在 Mac OS X 上,它是字节。

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

          如果您只关心 Linux,您也可以阅读 /proc/self/status/proc/self/statm 文件,如该问题的其他答案和this 中所述。

          【讨论】:

          • 好的,会的。我不确定SO是否有合并问题的流程或什么。重复的帖子部分是为了向人们展示关于这两个问题的标准库解决方案……部分是为了代表。 ;) 我应该删除这个答案吗?
          • Mac OS 肯定以字节为单位返回 RSS,Linux 以千字节为单位返回。
          • 单位不是千字节。它依赖于平台,因此您必须使用 resource.getpagesize() 来查找。给定的 Python 文档 (docs.python.org/2/library/resource.html#resource-usage) 实际上对此非常清楚。我的盒子里是 4096。
          • @BenLin 那些 Python 文档显然是错误的,或者 Mac 版本存在错误。 getrusage 使用的单位和 getpagesize 返回的值肯定是不一样的。
          • 问题询问当前的使用情况。请注意,这是最大使用量。 (仍然是一个有用的答案,只是警告那些错误地复制粘贴它的人。)
          【解决方案8】:

          对于 Python 3.6 和 psutil 5.4.5,使用列出的 memory_percent() 函数更容易here

          import os
          import psutil
          process = psutil.Process(os.getpid())
          print(process.memory_percent())
          

          【讨论】:

          • 这需要 lib psutil
          【解决方案9】:
          import os, win32api, win32con, win32process
          han = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION|win32con.PROCESS_VM_READ, 0, os.getpid())
          process_memory = int(win32process.GetProcessMemoryInfo(han)['WorkingSetSize'])
          

          【讨论】:

          • 这可以通过解释它的作用和工作原理来改进。
          • 基于返回的大数字(8 位数字)以及我没有做太多任何事情,我猜这必须是字节?所以对于一个相当空闲的交互式实例来说,它大约是 28.5 MB。 (哇......我什至没有意识到上面的评论是我 4 年前的......这很奇怪。)
          【解决方案10】:

          我喜欢it,感谢@bayer。我现在有一个特定的进程计数工具。

          # Megabyte.
          $ ps aux | grep python | awk '{sum=sum+$6}; END {print sum/1024 " MB"}'
          87.9492 MB
          
          # Byte.
          $ ps aux | grep python | awk '{sum=sum+$6}; END {print sum " KB"}'
          90064 KB
          

          附上我的进程列表。

          $ ps aux  | grep python
          root       943  0.0  0.1  53252  9524 ?        Ss   Aug19  52:01 /usr/bin/python /usr/local/bin/beaver -c /etc/beaver/beaver.conf -l /var/log/beaver.log -P /var/run/beaver.pid
          root       950  0.6  0.4 299680 34220 ?        Sl   Aug19 568:52 /usr/bin/python /usr/local/bin/beaver -c /etc/beaver/beaver.conf -l /var/log/beaver.log -P /var/run/beaver.pid
          root      3803  0.2  0.4 315692 36576 ?        S    12:43   0:54 /usr/bin/python /usr/local/bin/beaver -c /etc/beaver/beaver.conf -l /var/log/beaver.log -P /var/run/beaver.pid
          jonny    23325  0.0  0.1  47460  9076 pts/0    S+   17:40   0:00 python
          jonny    24651  0.0  0.0  13076   924 pts/4    S+   18:06   0:00 grep python
          

          参考

          【讨论】:

          • 只是代码的优化以避免多管道ps aux | awk '/python/{sum+=$6}; END {print sum/1024 " MB"}'
          【解决方案11】:

          使用 sh 和 os 进入 python bayer 的答案。

          float(sh.awk(sh.ps('u','-p',os.getpid()),'{sum=sum+$6}; END {print sum/1024}'))
          

          答案以兆字节为单位。

          【讨论】:

          • 应该注意 `sh' 不是标准库模块。不过,它可以通过 pip 安装。
          【解决方案12】:

          在 unix 上,您可以使用ps 工具对其进行监控:

          $ ps u -p 1347 | awk '{sum=sum+$6}; END {print sum/1024}'
          

          其中 1347 是某个进程 ID。此外,结果以 MB 为单位。

          【讨论】:

            猜你喜欢
            • 2014-08-21
            • 2011-12-15
            • 2023-04-05
            • 1970-01-01
            • 2020-10-19
            • 2012-11-16
            • 2015-11-05
            • 1970-01-01
            相关资源
            最近更新 更多