异常处理何时会意外影响对象生存期?



数据模型上的 Python 参考指出

使用"尝试...除了"声明可能会使物体保持活力。

异常更改控制流似乎相当明显,这可能导致不同的对象保持引用状态。为什么明确提到?这里是否有内存泄漏的可能性?

异常存储回溯,该回溯存储引发和例外之间的所有子帧("函数调用")。框架引用所有本地名称及其值,防止对本地名称和值进行垃圾回收。

这意味着异常处理程序应立即完成异常处理,以允许清理子局部变量。尽管如此,函数仍不能依赖于其局部变量在函数结束后立即可收集。

因此,RAII 等模式即使在引用计数实现上也不可靠。当需要提示清理时,对象应提供显式清理(用于finally块)或最好是自动清理(用于with块)的方法。

对象、值和类型

[...] 强烈建议程序显式关闭此类对象。try...finally' 语句和 'with' 语句提供了执行此操作的便捷方法。


可以使用一个类来观察这一点,该类标记了何时进行垃圾回收。

class Collectible:
def __init__(self, name):
self.name = name
def __del__(self, print=print):
print("Collecting", self.name)
def inner():
local_name = Collectible("inner local value")
raise RuntimeError("This is a drill")
def outer():
local_name = Collectible("outer local value")
inner()
try:
outer()
except RuntimeError as e:
print(f"handling a {type(e).__name__}: {e}")

在 CPython 上,输出显示处理程序在收集局部变量之前运行:

handling a RuntimeError: This is a drill
Collecting inner local value
Collecting outer local value

请注意,CPython使用引用计数,这已经导致尽快快速清理。其他实现可能会进一步任意延迟清理。

好吧,AFAIK,如果异常引用了某个对象或其他对象,则在收集异常本身之前不会收集这些对象,而且,如果except语句碰巧引用某个对象,那也会将其集合海报化,直到块结束。我想知道是否有其他不太明显的方式捕获异常可能会影响垃圾收集。

最新更新