Python 垃圾收集函数范围内不再引用的变量吗?
Does Python garbage collect variables that are no longer referenced while within the scope of a function?
在等待一个漫长的运行函数执行完毕时,我开始考虑垃圾收集器是否会清理对不再使用的变量的引用。
例如,我有一个函数:
def long_running_function():
x = MemoryIntensiveObject()
print id(x)
# lots of hard work done here which does not reference x
return
我很好奇解释器是否足够聪明,可以意识到 x 不再使用并且可以取消引用。它有点难以测试,因为我可以编写代码来检查它的引用计数,但是那会隐式地引用它,从而避免了这样做的原因。
我的想法是,也许当函数被解析并生成字节码时,它可能会以这样一种方式生成,当它不再被引用时允许它清理对象。
或者,答案是不是更简单,只要还在"could"使用范围内,就不会被清理?
不,只要引用该对象的名称仍在当前作用域中定义,CPython 就不会对对象进行垃圾回收。
这是因为,即使在代码中没有将名称 x
作为文字引用,调用 vars()
或 locals()
仍然可以获取局部变量的副本命名空间字典(在最后一次引用 x
之前或之后),因此整个本地命名空间有效地 "roots" 它引用的值,直到执行离开其范围。
我不确定其他实现是如何做到这一点的。特别是,在 PyPy、Jython 或 IronPython 等 JIT 编译实现中,至少在理论上可以执行此优化。 JVM 和 CLR JIT 实际上确实在其他语言上执行了这种优化。 Python 在这些平台上是否能够利用完全取决于 Python 代码被编译成的字节码。
在等待一个漫长的运行函数执行完毕时,我开始考虑垃圾收集器是否会清理对不再使用的变量的引用。
例如,我有一个函数:
def long_running_function():
x = MemoryIntensiveObject()
print id(x)
# lots of hard work done here which does not reference x
return
我很好奇解释器是否足够聪明,可以意识到 x 不再使用并且可以取消引用。它有点难以测试,因为我可以编写代码来检查它的引用计数,但是那会隐式地引用它,从而避免了这样做的原因。
我的想法是,也许当函数被解析并生成字节码时,它可能会以这样一种方式生成,当它不再被引用时允许它清理对象。
或者,答案是不是更简单,只要还在"could"使用范围内,就不会被清理?
不,只要引用该对象的名称仍在当前作用域中定义,CPython 就不会对对象进行垃圾回收。
这是因为,即使在代码中没有将名称 x
作为文字引用,调用 vars()
或 locals()
仍然可以获取局部变量的副本命名空间字典(在最后一次引用 x
之前或之后),因此整个本地命名空间有效地 "roots" 它引用的值,直到执行离开其范围。
我不确定其他实现是如何做到这一点的。特别是,在 PyPy、Jython 或 IronPython 等 JIT 编译实现中,至少在理论上可以执行此优化。 JVM 和 CLR JIT 实际上确实在其他语言上执行了这种优化。 Python 在这些平台上是否能够利用完全取决于 Python 代码被编译成的字节码。