Python中删除对象所有引用后__del__方法未被调用的原因是什么
原因分析
你遇到的这个现象最常见的诱因是Python交互式解释器(REPL)的隐式引用机制:
- Python REPL会将最近一次表达式的返回值自动存入特殊变量
_中,你之前执行a2查看对象地址的操作,返回值就是这个A类实例,所以该实例被_额外持有了一个引用。你删除a1、a2之后,_仍然指向该对象,引用计数没有归零,自然不会触发__del__方法。 - 你可以做个简单验证:删除
a2后执行del _,或者随便执行一条其他表达式(比如>>> 1+1)覆盖_的值,就会看到Object finalizer正常输出。
补充相关知识点
__del__方法的调用时机没有Python语言层面的严格强制保证,不同Python实现的行为差异很大:- CPython以引用计数为主要内存管理机制,正常情况下无循环引用的对象引用计数归零会立刻触发
__del__,但像上面提到的隐式引用、循环引用都会打破这个规律。 - PyPy等其他Python实现采用跟踪式垃圾回收,对象销毁时机更加不确定,
__del__可能要等到某次GC执行时才会触发,甚至可能直到程序退出才执行。
- CPython以引用计数为主要内存管理机制,正常情况下无循环引用的对象引用计数归零会立刻触发
- 如果对象涉及循环引用,且循环链中的任意对象定义了
__del__方法,CPython的循环垃圾回收器无法判断安全的销毁顺序,会直接将这些对象标记为不可回收,永远不会触发它们的__del__方法,还会造成内存泄漏。 - 生产环境中永远不要依赖
__del__做文件句柄、网络连接等资源的释放操作,它的执行时机不可控,甚至程序退出时都可能不执行,优先用上下文管理器(with语句)实现资源的自动安全释放。
# 验证示例,你的操作之后追加这行即可触发__del__ >>> del _ Object finalizer
内容的提问来源于stack exchange,提问作者Riccardo Bucco
相关产品推荐
相关产品推荐

