python对象销毁主要由引用计数归零触发,此时立即调用__del__并释放内存;但循环引用需gc模块清理,且异常帧、闭包等隐式强引用可能导致延迟销毁或内存泄漏。

Python对象的销毁时机主要由垃圾回收机制决定,核心是引用计数归零——当一个对象的引用计数降为0时,它会立即被销毁(调用__del__方法,并释放内存)。
引用计数何时减少
以下操作会使对象的引用计数减1:
- 变量被重新赋值(指向其他对象或
None) - 变量使用
del语句显式删除 - 函数执行结束,局部变量自动脱离作用域
- 容器(如列表、字典)被清空或删除,其中包含的对象引用被移除
引用归零即销毁:简单但有例外
大多数情况下,引用计数归零后对象立刻销毁。例如:
class A:
def __del__(self):
print("A is gone")
<p>a = A() # 引用计数=1
a = None # 原A对象引用计数→0 → 立即触发 <strong>del</strong>,输出 "A is gone"
但需注意:__del__不保证执行顺序,也不应在其中进行复杂操作(如修改全局状态、再创建同类对象),更不能依赖它做关键资源清理(应优先用with或显式close())。
立即学习“Python免费学习笔记(深入)”;
循环引用导致引用计数无法归零
两个或多个对象相互持有对方的引用,即使外部已无引用,它们的引用计数也不为0。此时CPython的引用计数机制无法回收,需依赖周期性运行的**循环垃圾收集器(gc模块)**来检测并清理。
例如:
import gc
class Node:
def __init__(self):
self.ref = None
def __del__(self):
print("Node deleted")
<p>a = Node()
b = Node()
a.ref = b
b.ref = a # 形成循环引用
del a, b # 引用计数未归零,但gc可后续回收(需启用且触发)
可通过gc.collect()手动触发回收,或用gc.set_debug(gc.DEBUG_COLLECTABLE)观察哪些对象被识别为可回收。
不可见引用:容易忽略的“拖尾”引用
某些场景下,对象看似已无引用,实则仍被隐式持有:
- 异常帧中保留了局部变量(如在
except块中访问了引发异常的函数栈帧) - 装饰器、闭包、lambda 捕获了外部变量
- 线程局部存储(
threading.local())、弱引用缓存、调试器(如pdb)等也可能延长生命周期
这类引用不会增加引用计数(如弱引用),但强引用若未被察觉,会导致对象延迟销毁甚至内存泄漏。










