为什么大小为2⁶³36字节,但2⁶³-1只有24字节?

T.N*_*Nel 51 python cpython python-2.7 python-internals

Python中的所有东西都是一个对象.因此Python中int的大小将比平常大.

>>> sys.getsizeof(int())
24
Run Code Online (Sandbox Code Playgroud)

好的,但为什么还需要12个字节才能进行2?³比较2?³ - 1,而不仅仅是一个?

>>> sys.getsizeof(2**63)
36
>>> sys.getsizeof(2**62)
24
Run Code Online (Sandbox Code Playgroud)

我得到的2?³是一个long和2?³-1一个int,但为什么12个字节的区别?

不再直观,我尝试了一些其他的东西:

>>> a = 2**63
>>> a -= 2**62
>>> sys.getsizeof(a)
36
Run Code Online (Sandbox Code Playgroud)

a即使它现在可以在int中,仍然存储为long.所以这并不奇怪.但:

>>> a -= (2**63 - 1)
>>> a = 2**63
>>> a -= (2**63 - 1)
>>> a
1L
>>> sys.getsizeof(a)
28
Run Code Online (Sandbox Code Playgroud)

一个新的尺寸.

>>> a = 2**63
>>> a -= 2**63
>>> a
0L
>>> sys.getsizeof(a)
24
Run Code Online (Sandbox Code Playgroud)

回到24个字节,但仍然很长.

我得到的最后一件事:

>>> sys.getsizeof(long())
24
Run Code Online (Sandbox Code Playgroud)

题:

内存存储在这些场景中如何工作?

子问题:

为什么有12个字节的间隙来添加我们的直觉告诉我们只有1位?

为什么int()long()24字节,但long(1)已经是28字节和int(2?²)

注意:Python 3.X的工作方式略有不同,但并不直观.在这里,我专注于Python 2.7; 我没有测试以前的版本.

use*_*342 62

为什么它为2⁶³增加12个字节,相比之下2⁶³-1而不仅仅是1?

LP64系统1上,Python 2 int 三个指针大小的部分组成:

  • 类型指针
  • 引用计数
  • 实际值,一个C. long int

这总共是24个字节.另一方面,Python long 包括:

  • 类型指针
  • 引用计数
  • 数字计数,指针大小的整数
  • 值的数字内联数组,每个值保存30位值,但以32位为单位存储(其中一个未使用的位用于在加法和减法期间进行有效的进位/借位)

2**63需要64位存储,因此它适合三个30位数字.由于每个数字的宽度为4个字节,因此整个Python long将需要24 + 3*4 = 36个字节.

换句话说,差异来自于long必须单独存储数字的大小(8个附加字节),并且与存储值相比空间效率稍差(12个字节用于存储2**63的数字).包括大小,值2**63在一个long占用20个字节.将其与简单的任何值占用的8个字节进行比较,int得出观察到的12字节差异.

值得注意的是,Python 3只有一个整数类型,称为int可变宽度,并以与Python 2相同的方式实现long.


1 的64位的Windows不同之处在于它保留了32位long int,据推测为具有大体的所用旧的代码源的兼容性char,shortlong对于如图8所示,也发生在工作16,和32位值作为"方便"的别名在16位和32位系统上.要在x86-64 Windows上获得实际的64位类型,必须使用__int64或(在较新的编译器版本上)long longint64_t.由于Python 2内部依赖于Python int在不同的地方适应C长,所以sys.maxint仍然存在2**31-1,即使在64位Windows上也是如此.这个怪癖也在Python 3中修复,它没有maxint的概念.

  • @CIsForCookies看看[header](https://github.com/python/cpython/blob/master/Include/longintrepr.h)和[实现](https://github.com/python/cpython) /blob/master/Objects/longobject.c). (4认同)
  • @chrisz您应该将其视为实施细节; 要告诉的唯一方法是查看有问题的解释器/编译器的来源,看看它的作用. (3认同)
  • @ user48:同意它不是*明显*,但请记住,非常量是`add`的操作数,所以它通常仍在寄存器中.事实证明我实际上已经写了一篇关于[让编译器生成`adc`]的答案(/sf/ask/3269095511/ 64位数字的使用-ASM-在-C).它比我记忆中的更糟糕,只有clang实际上使用了'adc`.此外,**[`sum <b`只是安全,没有随身携带!](/sf/ask/290769671/#comment53703145_4154170)**oops. (2认同)

CIs*_*ies 5

虽然我没有在文档中找到它,但这是我的解释.

当值超过可以存储在int中的值时,Python 2 intlong隐式提升.新类型(long)的大小是默认大小long,即32.从现在开始,变量的大小将由其值上下决定.

from sys import getsizeof as size
a = 1
n = 32

# going up
for i in range(10):
    if not i:
        print 'a = %100s%13s%4s' % (str(a), type(a), size(a))
    else:
        print 'a = %100s%14s%3s' % (str(a), type(a), size(a))
    a <<= n

# going down
for i in range(11):
    print 'a = %100s%14s%3s' % (str(a), type(a), size(a))
    a >>= n


a =                                                                                                    1 <type 'int'>  24
a =                                                                                           4294967296 <type 'long'> 32
a =                                                                                 18446744073709551616 <type 'long'> 36
a =                                                                        79228162514264337593543950336 <type 'long'> 40
a =                                                              340282366920938463463374607431768211456 <type 'long'> 44
a =                                                    1461501637330902918203684832716283019655932542976 <type 'long'> 48
a =                                           6277101735386680763835789423207666416102355444464034512896 <type 'long'> 52
a =                                 26959946667150639794667015087019630673637144422540572481103610249216 <type 'long'> 56
a =                       115792089237316195423570985008687907853269984665640564039457584007913129639936 <type 'long'> 60
a =              497323236409786642155382248146820840100456150797347717440463976893159497012533375533056 <type 'long'> 64
a =    2135987035920910082395021706169552114602704522356652769947041607822219725780640550022962086936576 <type 'long'> 68
a =              497323236409786642155382248146820840100456150797347717440463976893159497012533375533056 <type 'long'> 64
a =                       115792089237316195423570985008687907853269984665640564039457584007913129639936 <type 'long'> 60
a =                                 26959946667150639794667015087019630673637144422540572481103610249216 <type 'long'> 56
a =                                           6277101735386680763835789423207666416102355444464034512896 <type 'long'> 52
a =                                                    1461501637330902918203684832716283019655932542976 <type 'long'> 48
a =                                                              340282366920938463463374607431768211456 <type 'long'> 44
a =                                                                        79228162514264337593543950336 <type 'long'> 40
a =                                                                                 18446744073709551616 <type 'long'> 36
a =                                                                                           4294967296 <type 'long'> 32
a =                                                                                                    1 <type 'long'> 28
Run Code Online (Sandbox Code Playgroud)

正如你所看到的那样,类型long在第一次变得太大之后就停留了int,初始大小为32,但是大小随着值的变化而变化(可以更高或更低[或相等,显然]为32)

所以,为了回答你的问题,基本大小是24 for int,28 for long,while long还有用于保存大值的空间(从4个字节开始 - 因此32个字节long,但可以根据值上下)

至于你的子问题,为新数字创建一个唯一类型(具有唯一大小)是不可能的,因此Python有"子类" long类型,它处理一系列数字,因此,一旦超过限制你的旧的long你必须使用更新的,它也会占更大的数字,因此,它有更多的字节.