【问题标题】:Python's layout of low-value ints in memoryPython 在内存中的低值整数布局
【发布时间】:2010-02-03 22:28:41
【问题描述】:

我的问题是:这些模式(如下)起源于哪里?

我(在某处)了解到,对于小整数,Python 有独特的“副本”,如果这是正确的词的话。例如:

>>> x = y = 0
>>> id(0)
4297074752
>>> id(x)
4297074752
>>> id(y)
4297074752
>>> x += 1
>>> id(x)
4297074728
>>> y
0

当我查看int的内存位置时,很早就有一个简单的模式:

>>> N = id(0)
>>> for i in range(5):
...     print i, N - id(i)
... 
0 0
1 24
2 48
3 72
4 96
>>> bin(24)
'0b11000'

我不清楚为什么选择它作为增量。而且,我根本无法解释256以上的这种模式:

>>> prev = 0
>>> for i in range(270):
...     t = (id(i-1), id(i))
...     diff = t[0] - t[1]
...     if diff != prev:
...         print i-1, i, t, diff
...         prev = diff
... 
-1 0 (4297074776, 4297074752) 24
35 36 (4297073912, 4297075864) -1952
36 37 (4297075864, 4297075840) 24
76 77 (4297074904, 4297076856) -1952
77 78 (4297076856, 4297076832) 24
117 118 (4297075896, 4297077848) -1952
118 119 (4297077848, 4297077824) 24
158 159 (4297076888, 4297078840) -1952
159 160 (4297078840, 4297078816) 24
199 200 (4297077880, 4297079832) -1952
200 201 (4297079832, 4297079808) 24
240 241 (4297078872, 4297080824) -1952
241 242 (4297080824, 4297080800) 24
256 257 (4297080464, 4297155264) -74800
257 258 (4297155072, 4297155288) -216
259 260 (4297155072, 4297155336) -264
260 261 (4297155048, 4297155432) -384
261 262 (4297155024, 4297155456) -432
262 263 (4297380280, 4297155384) 224896
263 264 (4297155000, 4297155240) -240
264 265 (4297155072, 4297155216) -144
266 267 (4297155072, 4297155168) -96
267 268 (4297155024, 4297155144) -120

有什么想法、线索、要看的地方吗?

编辑:24 有什么特别之处?

更新:标准library 具有sys.getsizeof(),当我使用1 作为参数调用它时,它返回24。这是很多字节,但在 64 位机器上,类型、值和引用计数各有 8 个字节。另请参阅 here 和 C API 参考 here

在 cmets 中使用 Peter Hansen 链接中的“来源”花了一些时间。找不到 int 的定义(除了*int_int 的声明),但我确实找到了:

#define NSMALLPOSINTS       257
#define NSMALLNEGINTS       5

【问题讨论】:

  • “有什么想法、线索和地方可以看吗?”是的。阅读源代码。它会告诉你你想知道的一切。
  • 是的,但是源代码就像 C 或者什么的。 :) 我希望有一个 PEP 等价物。
  • PEP 不会指定这样的实现细节。如果你想知道类似这样的东西,它实际上不会影响(理智的)代码,它会在源代码中。
  • 不在 PEP 中,但也不在源中:docs.python.org/c-api/int.html#PyInt_FromLong(它的值从 -5 到 256)。

标签: python memory


【解决方案1】:

低值整数是预先分配的,高值整数是在计算时分配的。源代码中出现的整数是同一个对象。在我的系统上,

>>> id(2) == id(1+1)
True
>>> id(1000) == id(1000+0)
False
>>> id(1000) == id(1000)
True

您还会注意到 ID 取决于系统。它们只是内存地址,由系统分配器(或者可能是链接器,为静态对象分配?)

>>> id(0)
8402324

编辑:id(1000) == id(1000) 的原因是因为 Python 编译器注意到它正在编译的代码中的两个整数常量是相同的,所以它只为两者分配一个对象。这将在运行时对性能造成不可接受的影响,但在编译时并不明显。 (是的,解释器也是编译器。大多数解释器也是编译器,很少不是。)

【讨论】:

  • 具体(并且仅当前)它的值从 -5 到 256。在答案中解释为什么 id(1000) 案例返回 True 可能是个好主意。 (这是只有在向您解释后才相当明显的事情之一。)
【解决方案2】:

我似乎记得 Python 会在内部缓存 int

【讨论】:

    【解决方案3】:

    前 256 个整数是预分配的

    >>> for n in range(1000):
    >>>  if id(n) != id(n+0):
    >>>   print n
    >>>   break
    
    257
    

    【讨论】:

      【解决方案4】:

      由于其他人已经完全回答了为什么 id 具有高达 256 的不同模式,我想我会回答你的附录:24 是 python 中整数对象的字节大小。当分配前 256 个整数时,它们在内存中连续分配,导致每个内存地址之间的差异为 24。

      【讨论】:

        【解决方案5】:

        最多 256 的整数被保留,这就是为什么您会在那里看到“模式”。所有其他整数都是在执行期间创建的,因此随机分配id

        【讨论】:

        • 好的。 “随机”或其他,高于 256。
        【解决方案6】:

        在 CPython 中,IDs are the address of the objects

        【讨论】:

          猜你喜欢
          • 2010-10-03
          • 2019-05-02
          • 2018-08-26
          • 1970-01-01
          • 2013-06-25
          • 2023-03-22
          • 1970-01-01
          相关资源
          最近更新 更多