11

我试图准确/明确地找到 Python 中两个不同类之间的大小差异。它们都是新的样式类,除了一个没有定义插槽。我已经尝试了许多测试来确定它们的大小差异,但它们最终在内存使用方面总是相同的。

到目前为止,我已经尝试了 sys.GetSizeOf(obj) 和 heapy 的 heap() 函数,没有任何积极的结果。测试代码如下:

import sys
from guppy import hpy

class test3(object):
    def __init__(self):
        self.one = 1
        self.two = "two variable"

class test4(object):
    __slots__ = ('one', 'two')
    def __init__(self):
        self.one = 1
        self.two = "two variable"

test3_obj = test3()
print "Sizeof test3_obj", sys.getsizeof(test3_obj)

test4_obj = test4()
print "Sizeof test4_obj", sys.getsizeof(test4_obj)

arr_test3 = []
arr_test4 = []

for i in range(3000):
    arr_test3.append(test3())
    arr_test4.append(test4())

h = hpy()
print h.heap()

输出:

Sizeof test3_obj 32
Sizeof test4_obj 32

Partition of a set of 34717 objects. Total size = 2589028 bytes.
 Index  Count   %     Size   % Cumulative  % Kind (class / dict of class)
     0  11896  34   765040  30    765040  30 str
     1   3001   9   420140  16   1185180  46 dict of __main__.test3
     2   5573  16   225240   9   1410420  54 tuple
     3    348   1   167376   6   1577796  61 dict (no owner)
     4   1567   5   106556   4   1684352  65 types.CodeType
     5     68   0   105136   4   1789488  69 dict of module
     6    183   1    97428   4   1886916  73 dict of type
     7   3001   9    96032   4   1982948  77 __main__.test3
     8   3001   9    96032   4   2078980  80 __main__.test4
     9    203   1    90360   3   2169340  84 type
<99 more rows. Type e.g. '_.more' to view.>

这就是 Python 2.6.0 的全部内容。我还尝试覆盖类的sizeof方法,以尝试通过对各个 sizeof 求和来确定大小,但这并没有产生任何不同的结果:

class test4(object):
    __slots__ = ('one', 'two')
    def __init__(self):
        self.one = 1
        self.two = "two variable"
    def __sizeof__(self):
        return super(test4, self).__sizeof__() + self.one.__sizeof__() + self.two.__sizeof__()

覆盖sizeof方法的结果:

Sizeof test3_obj 80
Sizeof test4_obj 80
4

6 回答 6

5

sys.getsizeof返回一个比人们想象的更专业、更没用的数字。事实上,如果你将属性数增加到六个,你的 test3_obj 仍然是 32,但 test4_obj 会跳转到 48 个字节。这是因为 getsizeof 正在返回实现类型的 PyObject 结构的大小,对于 test3_obj 不包括保存属性的字典,但对于 test4_obj,属性不存储在字典中,它们存储在插槽中,所以它们被计入大小。

但是定义的类比没有定义的类__slots__占用更少的内存,正是因为没有字典来保存属性。

为什么要覆盖__sizeof__?你真正想要完成什么?

于 2012-07-02T21:24:47.473 回答
3

正如其他人所说,sys.getsizeof仅返回代表您的数据的对象结构的大小。因此,例如,如果您有一个不断向其中添加元素的动态数组,sys.getsizeof(my_array)则只会显示基础DynamicArray对象的大小,而不是其元素占用的不断增长的内存大小。

pympler.asizeof.asizeof()给出对象的大致完整尺寸,对您来说可能更准确。

from pympler import asizeof
asizeof.asizeof(my_object)  # should give you the full object size
于 2018-09-26T17:24:38.150 回答
1

首先在你的操作系统的内存管理器中检查 Pyton 进程的大小,没有很多对象。

其次制作许多一种对象并再次检查大小。

第三制作许多其他类型的对象并检查大小。

重复几次,如果每个步骤的大小保持大致相同,您就有了可比较的东西。

于 2012-07-03T08:04:36.613 回答
1

以下功能已在 Python 3.6、64 位系统中测试。它对我非常有用。(我从网上找到它并根据我的风格对其进行了调整,并添加了“插槽”功能。我无法再次找到原始来源。)

def getSize(obj, seen: Optional[Set[int]] = None) -> int:
  """Recursively finds size of objects. Needs: import sys """
  seen = set() if seen is None else seen

  if id(obj) in seen: return 0  # to handle self-referential objects
  seen.add(id(obj))

  size = sys.getsizeof(obj, 0) # pypy3 always returns default (necessary)
  if isinstance(obj, dict):
    size += sum(getSize(v, seen) + getSize(k, seen) for k, v in obj.items())
  elif hasattr(obj, '__dict__'):
    size += getSize(obj.__dict__, seen)
  elif hasattr(obj, '__slots__'): # in case slots are in use
    slotList = [getattr(C, "__slots__", []) for C in obj.__class__.__mro__]
    slotList = [[slot] if isinstance(slot, str) else slot for slot in slotList]
    size += sum(getSize(getattr(obj, a, None), seen) for slot in slotList for a in slot)
  elif hasattr(obj, '__iter__') and not isinstance(obj, (str, bytes, bytearray)):
    size += sum(getSize(i, seen) for i in obj)
  return size

现在对于以下类的对象,

class test3(object):
    def __init__(self):
        self.one = 1
        self.two = "two variable"

class test4(object):
    __slots__ = ('one', 'two')
    def __init__(self):
        self.one = 1
        self.two = "two variable"

得到以下结果,

In [21]: t3 = test3()

In [22]: getSize(t3)
Out[22]: 361

In [23]: t4 = test4()

In [25]: getSize(t4)
Out[25]: 145

欢迎提出改进功能的反馈。

于 2020-06-17T15:08:15.273 回答
0

您可能希望使用不同的实现来获取内存中对象的大小:

>>> import sys, array
>>> sizeof = lambda obj: sum(map(sys.getsizeof, explore(obj, set())))
>>> def explore(obj, memo):
    loc = id(obj)
    if loc not in memo:
        memo.add(loc)
        yield obj
        if isinstance(obj, memoryview):
            yield from explore(obj.obj, memo)
        elif not isinstance(obj, (range, str, bytes, bytearray, array.array)):
            # Handle instances with slots.
            try:
                slots = obj.__slots__
            except AttributeError:
                pass
            else:
                for name in slots:
                    try:
                        attr = getattr(obj, name)
                    except AttributeError:
                        pass
                    else:
                        yield from explore(attr, memo)
            # Handle instances with dict.
            try:
                attrs = obj.__dict__
            except AttributeError:
                pass
            else:
                yield from explore(attrs, memo)
            # Handle dicts or iterables.
            for name in 'keys', 'values', '__iter__':
                try:
                    attr = getattr(obj, name)
                except AttributeError:
                    pass
                else:
                    for item in attr():
                        yield from explore(item, memo)


>>> class Test1:
    def __init__(self):
        self.one = 1
        self.two = 'two variable'


>>> class Test2:
    __slots__ = 'one', 'two'
    def __init__(self):
        self.one = 1
        self.two = 'two variable'


>>> print('sizeof(Test1()) ==', sizeof(Test1()))
sizeof(Test1()) == 361
>>> print('sizeof(Test2()) ==', sizeof(Test2()))
sizeof(Test2()) == 145
>>> array_test1, array_test2 = [], []
>>> for _ in range(3000):
    array_test1.append(Test1())
    array_test2.append(Test2())


>>> print('sizeof(array_test1) ==', sizeof(array_test1))
sizeof(array_test1) == 530929
>>> print('sizeof(array_test2) ==', sizeof(array_test2))
sizeof(array_test2) == 194825
>>> 

如果您想得到答案,请确保您没有为此代码提供任何无限迭代器。

于 2013-08-13T19:02:28.670 回答
0

我遇到了类似的问题,最后写了自己的帮手来做脏活。在这里查看

于 2016-07-21T22:27:37.290 回答