← [ BACK_TO_NOTES ]

Python 垃圾回收

CPython 引用计数 + 分代循环垃圾回收;理解循环引用与 gc 模块边界。

#concept #growing #dev #python #python

[!info] related notes

Python 垃圾回收

这个概念为什么出现

两个对象互相引用时,引用计数无法归零。CPython 引入循环检测 GC。不懂会在排查“内存不降”时误判。

[!abstract] 一句话理解 CPython 用引用计数配合循环 GC;gc 模块用于观察和调试。回收时机与代际策略属于具体版本和构建的实现,不能替代显式资源管理。

最小可观察示例

场景:构造循环引用并手动收集

# cycle_gc_demo.py
# 业务意图:演示循环引用与 gc.collect。
# 教学点:循环需要 GC;实现细节。

import gc


class Node:
    def __init__(self, name: str) -> None:
        self.name = name
        self.ref = None


def main() -> None:
    gc.collect()
    a, b = Node("a"), Node("b")
    a.ref, b.ref = b, a  # 循环
    del a, b
    n = gc.collect()
    print("collected + uncollectable objects:", n)


if __name__ == "__main__":
    main()

建议运行:

python cycle_gc_demo.py

期望输出:collected + uncollectable objects: 后为非负整数。这是已收集对象与不可收集对象数量之和,不是循环数量;可能包含其他垃圾,不应断言恰好为 2。

结合场景再看三个关注点

  1. del 名字不等于立刻解开循环。
  2. gc.collect() 统计的是对象;一次循环可能涉及多个实例与容器。
  3. 循环本身不等于泄漏;弱引用适用于不应拥有对象的关系,不应机械替换所有强引用。

核心概念与准确模型

  • 引用计数
  • 代际与阈值行为需查目标补丁版本文档;例如 CPython 3.14 系列中代际策略已有调整。
  • 可调阈值(高级)
  • __del__ 与周期回收的复杂交互

边界情况与反直觉行为

  1. __del__ 复活对象
  2. gc.disable() 关闭自动循环收集,不会关闭引用计数,也不阻止显式 gc.collect()。
  3. gc 不是通用原生内存管理器;支持 GC 协议的扩展对象可参与循环检测,外部库缓冲仍需其释放协议。

常见误区

[!warning] 常见误区:Python 没有 GC 只有计数 错误理解:单机制。
正确模型:计数 + 循环 GC(CPython)。

工程实践

  • 缓存用弱引用/显式上限
  • 排查泄漏:对象增长曲线
  • 不要在业务里频繁玩 gc 旋钮

本节总结

GC 是安全网。设计上仍应管理对象生命周期与缓存边界。

自测题

  1. 循环引用为何难倒纯引用计数?
  2. __del__ 为何危险?
参考答案
  1. 互相持有导致计数永不为 0。
  2. 回收时机、顺序和对象复活使终结器难以推理;现代 CPython 通常能收集含 del 的循环,不能把有终结器直接等同于不可收集。

延伸阅读与资料来源

资料类型支撑内容
gc文档模块
Supporting Cyclic GCC-API实现向
创建于 2026/7/15 更新于 2026/10/6
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本