了解Python中大整数的内存分配

Vig*_*ren 31 python int python-3.x python-internals

Python如何为大整数分配内存?

一个int类型的大小28 bytes和随着我不断增加的值int,大小以增量为单位增加4 bytes.

  1. 为什么28 bytes最初的价值低至何1

  2. 为什么增量4 bytes

PS:我在x86_64(64位机器)上运行Python 3.5.2.关于(3.0+)解释器如何处理如此庞大的数字的任何指针/资源/ PEP都是我正在寻找的.

代码说明尺寸:

>>> a=1
>>> print(a.__sizeof__())
28
>>> a=1024
>>> print(a.__sizeof__())
28
>>> a=1024*1024*1024
>>> print(a.__sizeof__())
32
>>> a=1024*1024*1024*1024
>>> print(a.__sizeof__())
32
>>> a=1024*1024*1024*1024*1024*1024
>>> a
1152921504606846976
>>> print(a.__sizeof__())
36
Run Code Online (Sandbox Code Playgroud)

Jim*_*ard 25

为什么28字节最初的任何值都低至1

我相信@bgusach完全回答了这个问题 ; Python使用C结构来表示Python世界中的对象,包括ints的任何对象:

struct _longobject {
    PyObject_VAR_HEAD
    digit ob_digit[1];
};
Run Code Online (Sandbox Code Playgroud)

PyObject_VAR_HEAD是一个宏,当展开时在结构中添加另一个字段(字段PyVarObject专门用于具有一些长度概念的对象),并且ob_digits是一个包含数字值的数组.锅炉板尺寸来自该结构,适用于小型大型Python数字.

为什么增加4字节?

因为,当创建一个更大的数字时,大小(以字节为单位)是该数字的倍数sizeof(digit); 你可以看到在执行_PyLong_Newnew的内存分配的地方:longobjectPyObject_MALLOC

/* Number of bytes needed is: offsetof(PyLongObject, ob_digit) +
   sizeof(digit)*size.  Previous incarnations of this code used
   sizeof(PyVarObject) instead of the offsetof, but this risks being
   incorrect in the presence of padding between the PyVarObject header
   and the digits. */
if (size > (Py_ssize_t)MAX_LONG_DIGITS) {
    PyErr_SetString(PyExc_OverflowError,
                    "too many digits in integer");
    return NULL;
}
result = PyObject_MALLOC(offsetof(PyLongObject, ob_digit) +
                         size*sizeof(digit));
Run Code Online (Sandbox Code Playgroud)

offsetof(PyLongObject, ob_digit) 是长对象的'样板'(以字节为单位),与保持其值无关.

digit在头文件保持被定义struct _longobjecttypedefuint32:

typedef uint32_t digit;
Run Code Online (Sandbox Code Playgroud)

并且sizeof(uint32_t)4字节.当size参数增加时,您将看到以字节为单位的大小增加_PyLong_New量.


当然,这正是CPython选择实现它的方式.这是一个实现细节,因此您不会在PEP中找到太多信息.如果你能找到相应的线程,python-dev邮件列表将进行实现讨论:-).

无论哪种方式,您可能会在其他流行的实现中发现不同的行为,因此不要认为这是理所当然的.


bgu*_*ach 16

这实际上很容易.Python int不是你可能习惯于其他语言的原始类型,而是一个完整的对象,它的方法和所有东西.这就是开销来自的地方.

然后,您有自己的有效负载,即正在表示的整数.除了你的记忆,没有限制.

Python的大小int是表示数字加上一点开销所需要的.

如果您想进一步阅读,请查看文档相关部分:

整数具有无限的精度

  • @Vigneshwaren:您可以从[`sys.int_info`](https://docs.python.org/3/library/sys.html#sys.int_info)(2.7上的`long_info`)查看CPython的基本信息.基本上,每个绝对幅度的`sys.int_info.bits_per_digit`(符号无关)或其中的一部分需要额外的`sys.int_info.sizeof_digit`字节来存储.注意:小`int`s在CPython中缓存,因此作为实现细节,从(IIRC)-5到256的值是单例; 你只需要为引用它们的指针支付4-8个字节,而不是对象本身的成本. (3认同)
  • @Vigneshwaren这是您正在使用的任何解释器的实现细节.Python-the-language只保证`int`具有任意精度,而不是如何实现. (2认同)