【问题标题】:When does exception handling unexpectedly influence object lifetimes?异常处理何时会意外影响对象的生命周期?
【发布时间】:2022-01-11 13:22:14
【问题描述】:

Python reference on the data model 指出

使用“try...except”语句捕获异常可能会使对象保持活动状态。

异常改变控制流似乎相当明显,可能导致不同的对象仍然被引用。为什么明确提到它?这里有内存泄漏的可能性吗?

【问题讨论】:

    标签: python exception object-lifetime


    【解决方案1】:

    异常存储一个回溯,它存储引发例外之间的所有子帧(“函数调用”)。框架引用所有本地名称和它们的值,防止本地名称和值的垃圾收集。

    这意味着异常处理程序应立即完成对异常的处理,以便清理子本地。尽管如此,一个函数不能依赖于它的局部变量在函数结束后立即被收集。

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

    Objects, values and types

    […] 强烈建议程序显式关闭此类对象。 “tryfinally”语句和“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 使用引用计数,这已经导致尽快进行快速清理。其他实现可能会进一步任意延迟清理。

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-06-25
        • 1970-01-01
        • 1970-01-01
        • 2010-12-06
        • 1970-01-01
        • 2010-10-10
        • 2022-09-29
        相关资源
        最近更新 更多