我试图弄清楚究竟什么时候python对象是垃圾收集的候选对象。我已阅读了一些文件/帖子,但未能找到明确的答案。
以下面一行为例。这是foo的最后一个引用。 foo指向的对象何时可用于垃圾回收?
ret = func(['xyz: ' + foo.name])
将其分解为(可能的)个别步骤:
哪个对象首先有资格被收集?对象的引用计数何时递减?
如果步骤列表不完整/不正确,请告知我们。我只是试图列举它们,为潜在的参考答案提供一个共同的起点。
答案 0 :(得分:4)
与其他垃圾收集语言一样,经验法则是:当它无法访问时。这意味着,只要程序(它的任何部分)仍然可以访问它,就不能是gc'd。在那之后,这是公平的比赛。当(甚至是否)实际回收时,完全取决于实现。
在您的示例中,名称foo
使对象保持活动状态,因为程序仍可在以后的语句中使用它。 (理论上,实现可以检测是否不再使用变量,并删除该引用 - 可能使对象更快到达。实际上,这在Python中是不可能的,除非在JIT编译器编译的某些跟踪中。)列表,相反,如果func
在某些可到达的位置(例如,可到达对象的属性或全局变量)中没有存储对它的引用,则在执行func
之后或者甚至在它期间可能变得无法访问
请注意,你混淆了foo
和它所引用的对象,这在推理垃圾收集时是致命的。没有对象foo
,只有foo
在给定时间点引用的对象(从而在不同的时间点引用一组对象)。这很重要:
foo
以引用另一个对象,并且它最初引用的对象可能变得无法访问。除非你区分这两种情况,否则你不能谈论这种情况。foo
可能有许多其他引用指向(实际上很可能)。在foo
超出范围,被送到del
或更改为引用另一个对象后,可能会使对象保持很长时间。答案 1 :(得分:2)
只要对该变量的所有引用都超出范围或手动删除(del x
),该变量就有资格进行垃圾回收。
在您的示例中,foo
必须存在于此行之前(否则它是NameError
),因此永远不会在您的示例代码块中进行垃圾回收,因为此后引用仍将存在。即使在此之后要调用del foo
,我们也必须假定在其他地方没有对该对象的引用,因为它被垃圾收集。