一句话总览Python 的 GC 是“引用计数为主追踪式 GC 为辅”的混合模型引用计数负责 90% 的日常清理标记-清除解决循环引用分代回收降低性能损耗gc模块提供控制入口。第一部分引用计数Reference Counting——CPython 的基石1️⃣ 本质是什么在CPython中每一个 PyObject 都长这样简化typedefstruct_object{Py_ssize_t ob_refcnt;// 引用计数PyTypeObject*ob_type;// 类型对象}PyObject;ob_refcnt 就是一切的核心。2️⃣ 引用计数何时变化✅ 1 的情况对象被赋值作为参数传入函数加入容器list / dict / seta[]# 1ba# 2func(a)# 3临时引用lst[a]# 4❌ -1 的情况del变量变量被重新绑定离开作用域从容器中移除delb lst.pop()3️⃣ 对象销毁的完整流程当ob_refcnt 0调用该对象的__del__如果存在递归减少其内部引用的对象计数释放内存Pymalloc 或 malloc⚠️这是一个同步、无延迟的过程这也是 Python 不像 JVM 那样有明显 Stop-The-World 的原因之一。4️⃣ 优点 局限优点缺点实时回收无法处理循环引用实现直观维护计数的 CPU 开销无需 STW多线程下需要 GIL 保护结论引用计数是 Python GC 的“日常清洁工”但不是“终极解决方案”。第二部分标记-清除Mark-Sweep——解决循环引用1️⃣ 为什么必须有它a[]b[]a.append(b)b.append(a)deladelb引用计数 ≠ 0但程序再也访问不到它们内存泄漏发生 必须引入“可达性分析”。2️⃣ 核心思想非常关键“能被根对象访问到的就是活对象否则就是垃圾。”3️⃣ 谁是“根对象”全局变量当前调用栈中的局部变量CPU 寄存器中的临时引用4️⃣ 算法两阶段 标记阶段Mark从根对象出发DFS/BFS 遍历所有引用链Root ├─ Obj A ✅ ├─ Obj B ✅ └─ Obj C ✅ 清除阶段Sweep遍历堆中所有对象状态行为已标记保留未标记回收5️⃣ Python 的实现细节重点只处理容器对象list / dict / set / class instance使用双向链表维护“可收集对象”引入GC Head保存标记位structgc_generation{PyGC_Head head;};标记-清除不是用来替代引用计数的而是专门补它的短板。6️⃣ 典型误区纠正❌ “Python 靠 Mark-Sweep 回收所有对象”✅错只有循环引用才走这条路。第三部分分代回收Generational GC——性能优化的关键1️⃣ 分代假说GC 世界的公理大部分对象朝生夕死活得越久越可能继续活下去。2️⃣ Python 的三代模型代含义回收频率0 代新对象最高1 代熬过 1 次 GC中等2 代长期存活最低3️⃣ 晋升规则对象在第 0 代 GC 后仍存活 → 晋升到 1 代在第 1 代 GC 后仍存活 → 晋升到 2 代第 2 代对象几乎不被扫描4️⃣ 阈值机制非常重要gc.get_threshold()# (700, 10, 10)含义每新增700 个对象→ 触发 0 代 GC每执行10 次 0 代 GC→ 触发 1 代 GC每执行10 次 1 代 GC→ 触发 2 代 GC 这是一个指数衰减的扫描策略。5️⃣ 为什么不用 JVM 那种 Full GCPython 已有引用计数兜底全堆扫描代价太大分代 GC 是“最小必要扫描”第四部分gc模块——Python GC 的控制台1️⃣ 它是干什么的gc模块是对标记-清除 分代回收的封装接口。2️⃣ 核心 API 速查表方法作用gc.enable()启用 GCgc.disable()禁用 GCgc.isenabled()是否启用gc.collect(gen)手动回收gc.get_count()各代分配计数gc.get_threshold()阈值gc.set_threshold()设置阈值gc.garbage无法回收的对象3️⃣ 实际使用示例✅ 强制回收importgc gc.collect()✅ 调试内存泄漏gc.set_debug(gc.DEBUG_LEAK)✅ 查看不可回收对象print(gc.garbage)4️⃣__del__的“死亡陷阱”重点面试点classA:def__del__(self):print(A)classB:def__del__(self):print(B)a,bA(),B()a.bb b.aadeladelb❌ Python 不知道先调谁的__del__✅ 结果两个对象都被放入gc.garbage最佳实践不用__del__或用weakref或显式close()/dispose()五、四大机制关系总图逻辑闭环对象创建 │ ▼ 引用计数 1 │ ├── 引用归零 ──▶ 立即释放90% │ └── 循环引用 ──▶ 标记-清除 │ ▼ 分代回收调度 │ ▼ gc 模块控制六、常见面试追问必背Q1Python 会发生内存泄漏吗✅ 会。典型原因循环引用 __del__、全局缓存、C 扩展。Q2为什么 Python 不只用引用计数❌ 循环引用无法解决。Q3为什么 Python 不只用 Mark-Sweep❌ 实时性差STW 时间长。Q4Python GC 和 Java GC 的本质区别Java追踪式为主Python引用计数为主 追踪式为辅