python 的 gc - 从 get_count 获取对象

python's gc - get objects from get_count

我正在尝试了解 return 来自 gc.get_countgc.get_objects() 的值之间的差异。

首先,文档 (https://docs.python.org/3.8/library/gc.html) 说:

gc.get_count()

Return the current collection counts as a tuple of (count0, count1, count2).

gc.get_objects(generation=None)

Returns a list of all objects tracked by the collector, excluding the list returned. If generation is not None, return only the objects tracked by the collector that are in that generation.

现在,在一个简单的 REPL I 运行:

> import gc
> gc.get_count()
(692, 1, 1)
> len(gc.get_objects())
6372
> len(gc.get_objects(0))
771
> len(gc.get_objects(1))
490
> len(gc.get_objects(2))
5111
> gc.get_count()
(693, 1, 1)

所以从 get_count 开始,三代中总共有大约 700 个对象。 但是 get_objects return >6k 个对象。 我试图查看 DEBUG_SAVEALL,但它似乎与任何数字都没有关联(不在 get_count 中,也不在 get_objects 中)。

我的问题是:

  1. 为什么会出现差异? get_objects 中的对象与 get_count 中跟踪的对象之间的实际区别是什么? Whosebug 上有这两个问题:first and 但他们似乎没有回答差异。
  2. 我如何实际获取 get_count 中引用的对象(针对它的特定生成)?

谢谢!

所以我读了一些 CPython 实现 (https://github.com/python/cpython/blob/master/Modules/gcmodule.c),这是我学到的:

1)

基本上是 get_count(此处表示:https://github.com/python/cpython/blob/master/Modules/gcmodule.c#L1636-L1645) measures the amount of collections happened in a one level lower generation until that generation itself gets collected (See here: https://github.com/python/cpython/blob/master/Modules/gcmodule.c#L1211-L1212)。

因此,例如,当第 0 代(第一代)被收集时,第 1 代的计数增加 1。 第 0 代的计数在分配时增加,在释放时减少(收集在 #allocations - #deallocations > threashold 时开始)。

这回答了问题 (1) - 差异是因为它们是完全不同的东西。


2)

既然问题 1 已经回答了,问题 2 实际上是不相关的。

但是,我们可能会问一个不同的问题,即 “我如何跟踪为特定世代收集了哪些对象?”

在 Python 3.8 中,这是可能的,因为 get_objects 的接口已经改变,并且可以获取“属于”特定世代的对象。 考虑到这一点,可以注册一个回调(通过 gc.callbacks.append(callback_method)),它将通过在清理对象之前获取对象来跟踪该特定生成的集合(但请注意,您实际上不想强引用这些对象,否则您将仅通过测量来改变行为),然后获取它们并比较结果。


我会在一段时间内不接受这个答案,以便有机会获得其他答案,因为我正在回答我自己的问题。