为什么int需要三倍于Python的内存?

问题描述 投票:23回答:2

在64位系统上,Python中的整数需要24个字节。这是例如在例如所需的存储器的3倍。 C表示64位整数。现在,我知道这是因为Python整数是对象。但是用于的额外内存是多少?我有猜测,但肯定知道这会很好。

python object memory int python-internals
2个回答
32
投票

请记住,Python int类型没有像C int那样有限的范围;唯一的限制是可用内存。

内存用于存储值,整数存储的当前大小(存储大小可变以支持任意大小),以及标准Python对象簿记(对相关对象的引用和引用计数)。

你可以查找longintrepr.h source(Python 3 int类型传统上称为Python 2中的long类型);它有效地利用PyVarObject C type来跟踪整数大小:

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

ob_digit数组存储15或30位宽的“数字”(取决于您的平台);所以在我的64位OS X系统上,最多(2 ^ 30)-1的整数使用1'数字':

>>> sys.getsizeof((1 << 30) - 1)
28

但如果您在数字中使用2个30位数字,则需要额外的4个字节,等等:

>>> sys.getsizeof(1 << 30)
32
>>> sys.getsizeof(1 << 60)
36
>>> sys.getsizeof(1 << 90)
40

然后,基本24字节是PyObject_VAR_HEAD结构,包含对象大小,引用计数和类型指针(在我的64位OS X平台上每8字节/ 64位)。

在Python 2上,使用仅存储单个值的sys.maxint存储整数<= -sys.maxint - 1但是> = simpler structure

typedef struct {
    PyObject_HEAD
    long ob_ival;
} PyIntObject;

因为这使用PyObject而不是PyVarObject,结构中没有ob_size字段,内存大小仅限于24个字节; 8表示long值,8表示引用计数,8表示类型对象指针。


3
投票

从longintrepr.h,我们看到Python'int'对象是用这个C结构定义的:

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

数字是32位无符号值。大部分空间由可变大小的对象头部占用。从object.h,我们可以找到它的定义:

typedef struct {
    PyObject ob_base;
    Py_ssize_t ob_size; /* Number of items in variable part */
} PyVarObject;

typedef struct _object {
    _PyObject_HEAD_EXTRA
    Py_ssize_t ob_refcnt;
    struct _typeobject *ob_type;
} PyObject;

我们可以看到我们使用Py_ssize_t,64位假定64位系统,来存储值中“数字”的计数。这可能是浪费。我们还可以看到一般对象头具有64位引用计数,以及指向对象类型的指针,该指针也将是64位存储。引用计数是Python知道何时释放对象所必需的,并且指向对象类型的指针必须知道我们有一个int而不是一个字符串,因为C结构无法测试类型来自任意指针的对象。

_PyObject_HEAD_EXTRA在大多数python版本中都没有定义,但是如果构建启用了该选项,则可以使用它来存储堆上所有Python对象的链接列表,每个指针使用另外两个64位的指针。

© www.soinside.com 2019 - 2024. All rights reserved.