“sys.getsizeof(int)”返回一个不合理的大值?

时间:2012-04-28 16:59:16

标签: python

我想在python中检查int数据类型的大小:

import sys
sys.getsizeof(int)

它出现是“436”,对我来说没有意义。 无论如何,我想知道在我的机器上将占用多少字节(2,4,...?)。

1 个答案:

答案 0 :(得分:62)

简短回答

您获得的是的大小,而不是类的实例。调用int以获取实例的大小:

>>> sys.getsizeof(int())
24

如果该大小看起来仍然有点大,请记住Python int与(例如)c中的int非常不同。在Python中,int是一个完全成熟的对象。这意味着需要额外的开销。

除了其他存储之外,每个Python对象至少包含一个引用计数和对象类型的引用;在64位机器上,占用16个字节! int内部(由标准CPython实现确定)也随着时间的推移而发生变化,因此所需的额外存储量取决于您的版本。

Python 2和3中的int个对象的一些细节

这是Python 2中的情况。(其中一些改编自Laurent Luce的博客文章)。整数对象表示为具有以下结构的内存块:

typedef struct {
    PyObject_HEAD
    long ob_ival;
} PyIntObject;

PyObject_HEAD是一个定义refcount和对象类型存储的宏。 documentation对其进行了详细介绍,代码可以在this回答中看到。

内存以大块分配,因此每个新整数都没有分配瓶颈。块的结构如下所示:

struct _intblock {
    struct _intblock *next;
    PyIntObject objects[N_INTOBJECTS];
};
typedef struct _intblock PyIntBlock;

这些一开始都是空的。然后,每次创建一个新整数时,Python都会使用next指向的内存并递增next来指向块中的下一个空闲整数对象。

一旦超过普通整数的存储容量,我不完全确定这会如何变化,但一旦这样做,int的大小就会变大。在我的机器上,在Python 2中:

>>> sys.getsizeof(0)
24
>>> sys.getsizeof(1)
24
>>> sys.getsizeof(2 ** 62)
24
>>> sys.getsizeof(2 ** 63)
36

在Python 3中,我认为一般情况是相同的,但整数的大小会以更零散的方式增加:

>>> sys.getsizeof(0)
24
>>> sys.getsizeof(1)
28
>>> sys.getsizeof(2 ** 30 - 1)
28
>>> sys.getsizeof(2 ** 30)
32
>>> sys.getsizeof(2 ** 60 - 1)
32
>>> sys.getsizeof(2 ** 60)
36

这些结果当然都与硬件有关! YMMV。

Python 3中整数大小的可变性暗示它们可能更像是可变长度类型(如列表)。事实上,事实证明这是真的。以下是Python 3中int对象C struct的定义:

struct _longobject {
    PyObject_VAR_HEAD
    digit ob_digit[1];
};

此定义附带的comments总结了Python 3的整数表示。零不是由存储值表示,而是由大小为零的对象表示(这就是为sys.getsizeof(0)24字节而sys.getsizeof(1)28)的原因。负数由具有负大小属性的对象表示!太奇怪了。