2

我试图弄清楚python对象何时是垃圾收集的候选对象。我已经阅读了一些文件/帖子,但无法找到明确的答案。

以下面一行为例。这是对 foo 的最后一次引用。foo 指向的对象何时可用于垃圾回收?

ret = func(['xyz: ' + foo.name])

将其分解为(可能的)单个步骤:

  1. 创建对名称的临时引用。
  2. 'xyz:' 与名称连接并返回值。
  3. 列表是使用新字符串创建的。
  4. 使用新数组调用函数。
  5. 函数返回。
  6. 结果分配给ret。
  7. 下一个指令...

在哪两个步骤之间,对象首先有资格被收集?对象的引用计数何时减少?

如果步骤列表不完整/不正确,也请告诉我。我只是试图列举它们,为可能的参考答案提供一个共同的起点。

4

2 回答 2

4

与其他垃圾收集语言一样,经验法则是:当它无法访问时。这意味着,只要程序(它的任何部分)仍然可以访问它,就不能 gc'd。在那之后,这是公平的游戏。何时(甚至是否实际回收它完全取决于实现。

在您的示例中,该名称foo使对象保持活动状态,因为程序仍然可以在以后的语句中使用它。(理论上,一个实现可以检测一个变量是否不再使用,并删除该引用 - 可能使该对象更快无法访问。实际上,这在 Python 中是不可能的,除非在 JIT 编译器编译的某些跟踪中。)列表,相反,如果在某些可到达的位置(例如,可到达对象的属性或全局变量)不存储对它的引用,func则可能在执行之后甚至在执行期间变得不可访问。func

请注意,您混淆了foo它所指的对象,这在推理垃圾收集时是致命的。没有对象foo,只有一个foo在给定时间点引用的对象(因此,它在不同的时间点引用了一组对象)。这很重要:

  • foo可能会更改为引用另一个对象,并且它最初引用的对象可能变得无法访问。除非您区分这两种情况,否则您不能谈论这种情况。
  • 可能有许多其他对对象foo指向的引用(实际上很有可能)。foo在超出范围、被馈送到del或更改为引用另一个对象后,该对象可能会保持存活很长时间。
于 2012-12-03T19:34:25.373 回答
2

只要对该变量的所有引用超出范围或被手动删除(del x),该变量就可以进行垃圾回收。

在您的示例中,foo必须在此行之前存在(否则它是 a NameError),因此在您的示例代码块中永远不会被垃圾收集,因为在此之后引用仍然存在。即使有人del foo在此之后调用,我们也必须假定在其他任何地方都没有对该对象的引用,以便对其进行垃圾收集。

于 2012-12-03T19:26:35.150 回答