Python中小集合内存存储:为何空集合仅占用216字节?
为什么Python空集合的sys.getsizeof返回216字节而非预期的344字节?
先观察元素数量低于50k的集合扩容行为:
>>> import sys >>> s = set() >>> seen = {} >>> for i in range(50_000): ... size = sys.getsizeof(s) ... if size not in seen: ... seen[size] = len(s) ... print(f"{size=} {len(s)=}") ... s.add(i) ... size=216 len(s)=0 size=728 len(s)=5 size=2264 len(s)=19 size=8408 len(s)=77 size=32984 len(s)=307 size=131288 len(s)=1229 size=524504 len(s)=4915 size=2097368 len(s)=19661
这个扩容模式符合集合填充至3/5时后备存储容量四倍扩容的逻辑,结合PySetObject的固定开销,可通过计算验证:
>>> for i in range(9, 22, 2): ... print(2**i + 216) ... 728 2264 8408 32984 131288 524504 2097368
更大的集合会将扩容因子从四倍改为两倍,逻辑一致。
但这里存在疑问:新建空集合按说在首次扩容前有8个可用槽位,计算内存占用应为16*8 + 216 = 344字节,但sys.getsizeof(s)仅返回216字节,这是为什么?
核心原因:小集合的内部存储优化
你忽略了CPython对小集合的内存优化设计:
内置内部存储数组
CPython 3.11+的PySetObject结构体本身预留了小型内部存储数组,可容纳最多4个元素。这部分内存已经包含在sys.getsizeof返回的216字节中,不需要额外分配外部堆内存。外部数组延迟分配
只有当集合元素数量超过内部数组容量(即添加第5个元素时),解释器才会分配外部哈希表数组(初始容量32槽位,大小为32*16=512字节)。此时sys.getsizeof会将结构体大小与外部数组大小相加,得到216+512=728字节,与实验结果完全匹配。344字节计算的错误前提
你假设空集合会分配8槽位的外部数组,但实际上空集合和元素数量≤4的集合根本不会分配外部数组,而是使用结构体内部的预留空间。这部分空间已计入PySetObject的基础大小,因此不会额外增加内存占用。
内容的提问来源于stack exchange,提问作者wim
相关产品推荐
相关产品推荐

