首页 > 解决方案 > 了解 Cpython 垃圾收集生成

问题描述

我正在努力提高对 python 中内存管理如何工作的理解,但我对 python 垃圾收集器模块中的世代概念感到困惑。

我的理解如下:

所有创建的对象都从第 0 代开始,一旦达到阈值(第 0 代默认为 700),python 将在该代运行一个集合,并且任何幸存的对象都会老化到下一代。

鉴于上述情况,我无法理解以下输出。

import gc
import sys
x = 1
print(gc.get_count())
gc.collect()
print(gc.get_count())

输出

(64, 1, 1)
(0, 0, 0)

首先,我只运行了 1 行代码,并且我已经在 gen 1 和 2 中获得了对象,这意味着垃圾收集已经发生了至少两次,这怎么可能?无论如何要找出每一代中的对象是什么?其次,为什么我在收集后的所有世代中都有 0 引用?我仍然可以运行命令print(x)并且不会出错。这是否意味着仍然存在对 x 的引用,因此它应该存在于某一代中?

标签: python-3.xgarbage-collectioncpythonpython-internals

解决方案


gc.get_count()向您显示每一代的计数器,朝向阈值。

不是每一代对象的数量,而是计数器,当它到达线程持有时,该代的收集将发生。

例如,如果我从(0,0,0)计数器开始,运行x = [[] for i in range(100)]会将计数器设置为(101,0,0).

运行y = [[] for i in range(600)]将导致计数器翻转(0,1,0)gen0运行收集。在这一点上,我的所有列表都将移至gen1它们在gen0收藏中幸存下来。

当计数器到达(699,699,0)并分配另一个对象时,gen0gen1发生收集并且计数器将转到(0,0,1). 当 counter 达到(699,699,699),并且分配了一个对象,或者您使用gc.collect()(运行gen2集合)时, counter 将重置回(0,0,0).

要获取每一代中的对象,请使用gc.get_objects(gen).

关于代码运行之前的垃圾收集 - 当 Python 启动时,它会在加载脚本之前创建大量对象。例如,您可以看到通过运行加载的模块sys.modules。创建这些对象后,垃圾收集器会自动运行。


推荐阅读