在64位系统中,Python的整数占用24个字节。相比于C语言在64位系统中只需8个字节来存储整型变量,Python整数占用的内存是其3倍之多。这是因为Python的整数是对象所致。那么,这额外的内存用于什么呢?我有我的猜测,但最好知道确切原因。
请记住,Python int
类型不像 C 的 int
类型一样有限制范围;唯一的限制是可用内存。
内存用于存储值,当前整数存储的大小(存储大小可变以支持任意大小),以及标准 Python 对象记录(相关对象的引用和引用计数)。
您可以查看longintrepr.h
源代码(Python 3 中的 int
类型在 Python 2 中传统上被称为 long
类型);它有效地使用了PyVarObject
C 类型来跟踪整数大小:
struct _longobject {
PyObject_VAR_HEAD
digit ob_digit[1];
};
ob_digit
数组存储的是15或30位宽度的“数字”(取决于您的平台);因此在我的64位OS X系统上,最大整数为(2 ^ 30) - 1使用了1个“digit”:
>>> 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
的整数使用更简单的结构仅存储单个值:
typedef struct {
PyObject_HEAD
long ob_ival;
} PyIntObject;
由于使用了PyObject
而不是PyVarObject
,因此在结构体中没有ob_size
字段,并且内存大小仅限于24个字节;8个用于long
值,8个用于引用计数和8个用于类型对象指针。
ob_digits
条目,则ob_size
为2
或-2
,后者表示它是负整数。 - Martijn Pieters从longintrepr.h文件中,我们可以看到Python的'int'对象是使用以下C结构定义的:
struct _longobject {
PyObject_VAR_HEAD
digit ob_digit[1];
};
Digit是一个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;