Python 与sys.getsizeof()的结果相比,整数的内存占用较大
范围Python 与sys.getsizeof()的结果相比,整数的内存占用较大,python,python-3.x,performance,cpython,python-internals,Python,Python 3.x,Performance,Cpython,Python Internals,范围[1,2^30)中的Python整数对象需要28字节,如sys.getsizeof()所提供,并在中进行了示例说明 但是,当我使用以下脚本测量内存占用时: #int_list.py: import sys N=int(sys.argv[1]) lst=[0]*N # no overallocation for i in range(N): lst[i]=1000+i # ints not from integer pool 通过 因此,似乎每个整数对
[1,2^30)
中的Python整数对象需要28
字节,如sys.getsizeof()
所提供,并在中进行了示例说明
但是,当我使用以下脚本测量内存占用时:
#int_list.py:
import sys
N=int(sys.argv[1])
lst=[0]*N # no overallocation
for i in range(N):
lst[i]=1000+i # ints not from integer pool
通过
因此,似乎每个整数对象需要40.5
字节,即12.5
字节比sys.getsizeof()
产生的字节多
额外的8
字节很容易解释-列表lst
不包含整数对象,而是引用它们-这意味着需要额外的指针,即8
字节
但是,另一个4.5
字节呢,它们的用途是什么
可以排除以下原因:
- 整数对象的大小是可变的,但
小于10^7
,因此所有整数都将2^30
字节大28
- 列表
中没有过度分配,可以通过lst
轻松检查,它产生sys.getsizeof(lst)
8倍的元素数,外加非常小的开销
- int对象只需要28个字节,但Python使用8字节对齐方式:内存分配在大小为8字节倍数的块中。因此每个int对象实际使用的内存为32字节。有关详细信息,请参阅上的这篇优秀文章
对于剩余的半字节我还没有解释,但如果我找到了,我会更新它。@Nathan的建议出乎意料地不是解决方案,因为CPython的
longint
-实现有一些微妙的细节
...
lst[i] = (1<<30)+i
尽管事实上,
sys.sizeof(1实际上是一个很好的猜测!但是情况更微妙。请参阅我的答案(也解释了0.5字节)。
N Peak memory in Kb bytes/integer
-------------------------------------------
1 9220
1e7 404712 40.50
2e7 800612 40.52
3e7 1196204 40.52
4e7 1591948 40.52
...
lst[i] = (1<<30)+i
...
lst[i] = (1<<60)+i
static PyLongObject *
x_add(PyLongObject *a, PyLongObject *b)
{
Py_ssize_t size_a = Py_ABS(Py_SIZE(a)), size_b = Py_ABS(Py_SIZE(b));
PyLongObject *z;
...
/* Ensure a is the larger of the two: */
...
z = _PyLong_New(size_a+1);
...
...
return long_normalize(z);
/* Pool for small blocks. */
struct pool_header {
union { block *_padding;
uint count; } ref; /* number of allocated blocks */
block *freeblock; /* pool's free list head */
struct pool_header *nextpool; /* next pool of this size class */
struct pool_header *prevpool; /* previous pool "" */
uint arenaindex; /* index into arenas of base adr */
uint szidx; /* block size class index */
uint nextoffset; /* bytes to virgin block */
uint maxnextoffset; /* largest valid nextoffset */
};
/* Return total number of blocks in pool of size index I, as a uint. */
#define NUMBLOCKS(I) ((uint)(POOL_SIZE - POOL_OVERHEAD) / INDEX2SIZE(I))