Python分代垃圾回收:gc.get_count未正确报告创建对象数量?
Python分代垃圾回收计数异常问题解析
你创建了30000个Dummy对象,但最后一次gc.get_count()的结果并未如预期反映这个数量,以下是问题代码、实际输出及原因解析:
问题代码
import gc print(gc.get_threshold()) print(gc.get_count()) print(gc.collect()) print(gc.get_count()) class Dummy: def __init__(self) -> None: pass list = [] for i in range(10000): list.append(Dummy()) print(gc.get_count()) print(gc.collect()) for i in range(10000): list.append(Dummy()) print(gc.get_count()) print(gc.collect()) for i in range(10000): list.append(Dummy()) print(gc.get_count()) print(gc.collect())
实际运行输出
(700, 10, 10) (415, 0, 9) 391 (259, 0, 0) (54, 3, 1) 287 (522, 2, 1) 35 (526, 2, 1)
原因解析
首先明确Python分代垃圾回收的核心逻辑:
GC会根据对象存活的回收次数将其分为三代。新创建的对象会被放入最年轻的代(第0代)。如果对象在一次回收中存活下来,就会被移到更老的一代。第2代是最老的代,对象在回收后会保留在该代中。
收集器通过跟踪自上次回收以来的对象分配与释放数量决定何时触发回收:当分配数减去释放数超过threshold0时,回收启动,最初仅检查第0代;如果自上次检查第1代以来,第0代已被检查超过threshold1次,则同时检查第1代;第2代的触发逻辑相对复杂,可参考官方文档中"Collecting the oldest generation"部分。
你的代码中,每次创建10000个对象后都主动调用了gc.collect(),这会触发垃圾回收:
- 第一次创建10000个
Dummy对象并加入list,这些对象都是存活的,回收时不会被清理,但会从第0代晋升到第1代(因为在第0代回收中存活),所以gc.get_count()的第0代计数不会是10000,而是回收后的剩余计数加上后续操作的分配释放差值。 - 后续两次创建对象并调用
gc.collect()时,存活的对象会继续在代间晋升,同时gc.get_count()返回的是各代当前的分配释放差值累计,而非当前存活对象的总数。gc.get_count()的三个值分别对应:- 第0代:自上次第0代回收以来,分配数减去释放数的差值
- 第1代:自上次第1代回收以来,第0代被回收的次数
- 第2代:自上次第2代回收以来,第1代被回收的次数
你预期的30000是存活对象总数,但gc.get_count()并不统计存活对象数量,而是跟踪触发回收的阈值相关计数,这就是结果不符合预期的核心原因。如果要统计存活的Dummy对象数量,可以用以下代码:
print(len([obj for obj in gc.get_objects() if isinstance(obj, Dummy)]))
内容的提问来源于stack exchange,提问作者user3761555
相关产品推荐
相关产品推荐

