我一直试图更好地理解在通过追加扩展列表时,Python如何为列表分配内存.这question很好地涵盖了基本内容,并解释了随着列表长度的增加,内存增量的大小增加的原因.这article是对可以找到here的源代码的解释.

我想问一下这个解释:

/* This over-allocates proportional to the list size, making room
 * for additional growth.  The over-allocation is mild, but is
 * enough to give linear-time amortized behavior over a long
 * sequence of appends() in the presence of a poorly-performing
 * system realloc().
 * Add padding to make the allocated size multiple of 4.
 * The growth pattern is:  0, 4, 8, 16, 24, 32, 40, 52, 64, 76, ...
 * Note: new_allocated won't overflow because the largest possible value
 *       is PY_SSIZE_T_MAX * (9 / 8) + 6 which always fits in a size_t.
 */
新分配=((大小_t)新大小+(新大小;&>3)+6)&~(大小_t)3;
/* Do not overallocate if the new size is closer to overallocated size
 * than to the old size.
 */

具体来说,这个计算:

新分配=((大小_t)新大小+(新大小;&>3)+6)&~(大小_t)3;

我对这个计算的理解是,新的内存分配将等于newsize(触发增加的当前大小)+newsize右滚三位(有效除以8)+6. 然后将其与1的补数3进行AND运算,因此最后两位被强制为零,以使该值可被4整除.

我使用这个代码生成我的列表并报告大小:

a = [i for i in range(108)]
print(sys.getsizeof(a))  # 920 bytes

b = [i for i in range(109)]
print(sys.getsizeof(b))  # 1080 bytes

在109个元素时,触发了重新调整大小,此时newsize等于928字节

The calculation above should look like this: Binary calculation

1048字节小于报告的1060字节大小.

文档指出,这个过程可能不适合小列表,所以我try 了一个更大的列表. 我不会用二进制复制这个.

a = [i for i in range(10640)]
print(sys.getsizeof(a))  # 85176 bytes

b = [i for i in range(10641)]
print(sys.getsizeof(b))  # 95864 bytes

[85184+(86184>>3)+6]=95838bytes

当应用"~3"时,该值将下降到95836.& 第95864章报道

为什么报告的大小大于计算的大小?

推荐答案

我认为你的错误是你在字节上做这个计算.您必须在元素上执行此操作,然后添加空列表对象的开销.

下面是一个[i for i in range(109)]的快速模拟:

size = 0
used = 0
for _ in range(109):
    used += 1
    if used > size:
        size = (used + ((used >> 3) + 6)) & ~3

print(f"allocated array size: {size * 8}")
print(f"full list size: {size * 8 + sys.getsizeof([])}")
print(f"should be the same as {sys.getsizeof([i for i in range(109)])}")

数组大小:1024

完整列表大小:1080

与1080相同

8的因子在C中为sizeof(void*),在32位系统中为4.

Python相关问答推荐

如何使用Python将工作表从一个Excel工作簿复制粘贴到另一个工作簿?

沿着数组中的轴计算真实条目

. str.替换pandas.series的方法未按预期工作

查找两极rame中组之间的所有差异

从numpy数组和参数创建收件箱

如何记录脚本输出

pandas滚动和窗口中有效观察的最大数量

如何在Raspberry Pi上检测USB并使用Python访问它?

OR—Tools中CP—SAT求解器的IntVar设置值

在pandas数据框中计算相对体积比指标,并添加指标值作为新列

剪切间隔以添加特定日期

Gekko中基于时间的间隔约束

Cython无法识别Numpy类型

Polars Group by描述扩展

Beautifulsoup:遍历一个列表,从a到z,并解析数据,以便将其存储在pdf中.

BeautifulSoup-Screper有时运行得很好,很健壮--但有时它失败了::可能这里需要一些更多的异常处理?

类型对象';敌人';没有属性';损害';

多索引数据帧到标准索引DF

如何在PYTHON中向单元测试S Side_Effect发送额外参数?

时间戳上的SOAP头签名无效