【问题标题】:How can I check the memory usage of objects in iPython?如何检查 iPython 中对象的内存使用情况?
【发布时间】:2010-10-08 12:13:12
【问题描述】:

我正在使用 iPython 运行我的代码。我想知道是否有任何模块或命令可以让我检查对象的内存使用情况。例如:

In [1]: a = range(10000)
In [2]: %memusage a
Out[2]: 1MB

类似%memusage <object> 并返回对象使用的内存。

重复

Find out how much memory is being used by an object in Python

【问题讨论】:

标签: python memory ipython


【解决方案1】:

很遗憾,这是不可能的,但有多种方法可以近似得出答案:

  1. 对于或多或少表示为简单 C 语言类型的非常简单的对象(例如整数、字符串、浮点数、双精度数),您可以像 John Mulder's solution 一样简单地计算字节数。

  2. 对于更复杂的对象,一个很好的近似方法是使用 cPickle.dumps 将对象序列化为字符串。字符串的长度很好地近似于存储对象所需的内存量。

解决方案 2 有一个很大的障碍,即对象通常包含对其他对象的引用。例如,字典包含字符串键和其他对象作为值。那些其他对象可能是共享的。由于 pickle 总是尝试对对象进行完整的序列化,它总是会高估存储对象所需的内存量。

【讨论】:

  • 但是如果你挑选一个包含所有你感兴趣的根对象的列表,就不会高估了。
  • 非常感谢。但我想知道泡菜是否会做任何压缩。
  • 不,pickle 不压缩。它只是消除了冗余。
  • 在 SO 上没有 'above' 解决方案。
  • Salim:消除冗余是压缩的一种定义 :) 我最近尝试创建一个包含 10,000 个相似字符串的数组,并使用 Pickle 查看内存消耗。它将它存储为字符串一次,然后每次重复存储一个字节。然而,这并没有告诉我这个字符串的内部存储器表示(它可能相同,也可能不同)。
【解决方案2】:

如果您使用的是numpy array,那么您可以使用属性ndarray.nbytes 来评估它在内存中的大小:

from pylab import *   
d = array([2,3,4,5])   
d.nbytes
#Output: 32

【讨论】:

    【解决方案3】:

    更新:这里是another,可能是估计python对象大小的更彻底的方法。

    这是thread 解决类似问题

    建议的解决方案是编写自己的...使用对已知原语大小、python 的对象开销和内置容器类型大小的一些估计。

    由于代码不长,这里直接复制:

    def sizeof(obj):
        """APPROXIMATE memory taken by some Python objects in 
        the current 32-bit CPython implementation.
    
        Excludes the space used by items in containers; does not
        take into account overhead of memory allocation from the
        operating system, or over-allocation by lists and dicts.
        """
        T = type(obj)
        if T is int:
            kind = "fixed"
            container = False
            size = 4
        elif T is list or T is tuple:
            kind = "variable"
            container = True
            size = 4*len(obj)
        elif T is dict:
            kind = "variable"
            container = True
            size = 144
            if len(obj) > 8:
                size += 12*(len(obj)-8)
        elif T is str:
            kind = "variable"
            container = False
            size = len(obj) + 1
        else:
            raise TypeError("don't know about this kind of object")
        if kind == "fixed":
            overhead = 8
        else: # "variable"
            overhead = 12
        if container:
            garbage_collector = 8
        else:
            garbage_collector = 0
        malloc = 8 # in most cases
        size = size + overhead + garbage_collector + malloc
        # Round to nearest multiple of 8 bytes
        x = size % 8
        if x != 0:
            size += 8-x
            size = (size + 8)
        return size
    

    【讨论】:

    • 这是一个相当硬编码的解决方案。如果我们有一个大型字典列表或任何其他数据结构,这将不起作用!
    【解决方案4】:

    我试图弄清楚如何为自己做到这一点。我在此页面和其他页面上尝试了几种解决方案。然后我进行了一些搜索,发现https://ipython-books.github.io/44-profiling-the-memory-usage-of-your-code-with-memory_profiler/ 似乎提供了另一种解决方案。解决方案的要点:在 ipython 中使用%mprun

    1. 首先,安装memory_profiler:pip install memory_profiler
    2. 启动 ipython 并加载 memory_profiler:%load_ext memory_profiler
    3. 在物理文件中创建一个函数,例如myfunc.py(重要:%mprun 只能用于物理文件中定义的函数)。在函数中创建有问题的对象,例如:
    # myfunc.py
    def myfunc():
        # create the object, e.g.
        a = [*range(10000)]
    
    1. 运行
    from myfunc import myfunc
    %mprun -T mprof -f myfunc myfunc()
    

    生成文件 mprof.内容也显示出来了:

    Line #    Mem usage    Increment   Line Contents
    ================================================
         1     49.1 MiB     49.1 MiB   def myfunc():
         2                                 # create the object, e.g.
         3     49.4 MiB      0.3 MiB       a = [*range(10000)]
    

    根据第 3 行的内容,我们知道a 使用的内存为 0.3 MiB。

    让我们试试a = [*range(100000)]:

    # myfunc1.py
    def myfunc1():
        # create the object, e.g.
        a = [*range(100000)]
    

    运行

    from myfunc1 import myfunc1
    %mprun -T mprof1 -f myfunc1 myfunc1()
    
    Line #    Mem usage    Increment   Line Contents
    ================================================
         1     49.2 MiB     49.2 MiB   def myfunc1():
         2                                 # create the object, e.g.
         3     52.3 MiB      3.0 MiB       a = [*range(100000)]
    

    似乎符合我们的预期。

    【讨论】:

      猜你喜欢
      • 2016-01-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-09
      • 2017-04-20
      • 2010-10-08
      • 2014-07-30
      相关资源
      最近更新 更多