引用多一个计数加 1、减到 0 自动释放;两个对象互相引用时计数永不为 0,所以要另一套扫环的机制。
4.16 管失败的边界,这一节管对象的生死边界。
一、手写 free 的两种错
忘了放——内存泄漏,跑得越久越吃紧。 放了两次——野指针,崩得莫名其妙。 这两种错都不是【不会写】,是【人记不住】:谁该在什么时候放,分散在成千上万行里。
二、引用计数实测
b = Big() 之后 sys.getrefcount(b) 是 2(含 getrefcount 自己那一份)。
holder = [b] 之后变成 3;del holder 之后回到 2。
引用多一个,计数加 1;引用没了,减 1;减到 0 自动释放。
这是最直观的一种回收:不用扫全图,只看每个对象身上挂了几根线。
三、死穴:环
x.peer = y; y.peer = x——两个对象互相引用,计数永远不为 0。
即使把 x 和 y 都 del 掉,这两块内存也回收不了。
所以 Python 另有一套【分代回收】专门扫这种环:把对象按【活了几轮】分成几代,老对象扫得少。
这说明一件事:没有一种回收策略是全能的。
四、追踪式回收与代价
Java/C# 干脆不用引用计数,只用追踪式回收——从【根】(栈、静态区)出发,能走到的都留着,走不到的清掉。 好处是环也能收;代价是回收时要停下程序扫一遍,会停顿。 所以【垃圾回收不是免费的】——你用【不用想释放】换了【偶尔卡一下】。 这正是 4.13 说的那笔账:省下的活儿,代价总在别处。
五、动手 Demo:进化的 OOP 结构之三——垃圾回收
数一数一个对象被引用了几次,看计数怎么变。 再造一对互相引用的对象,看引用计数的死穴在哪。
import sys
b = Obj()
print(sys.getrefcount(b)) # 2:变量 + 传参
holder = [b]
print(sys.getrefcount(b)) # 3
holder.clear()
print(sys.getrefcount(b)) # 回到 2
x.peer, y.peer = y, x # 互相引用
# 即使 del x, y,计数也不为 0
实跑输出:
--------------------------------------------------------------------
进化的 OOP 结构之三——垃圾回收
--------------------------------------------------------------------
实例一多,**谁负责销毁**就成了问题。手写 `free` 会有两种错:**忘了放、放了两次。**
Python 用引用计数解决第一种:
b = Big()
sys.getrefcount(b) → 2(含 getrefcount 自己那一份)
holder = [b] 之后 → 3
del holder 之后 → 2
实测:**引用多一个,计数加 1;引用没了,计数减 1;减到 0 就自动释放。**
但引用计数有个死穴:**两个对象互相引用,计数永远不为 0。**
x.peer = y; y.peer = x
即使 del 掉 x 和 y,这两块内存也回收不了
→ 所以 Python 另有一套【分代回收】专门扫这种环
**Java/C# 干脆不用引用计数,只用追踪式回收**——从【根】出发能走到的都留着。
**代价是回收时会停顿**:这正是 4.17 说的【垃圾回收不是免费的】。
实测:引用加 1 计数加 1、引用去掉减 1、减到 0 就释放(2 → 3 → 2)。 两个对象互相引用时计数永不为 0,所以要另一套分代回收扫环;Java/C# 用追踪式回收,代价是停顿。
30 秒实验
- 用
sys.getrefcount观察一个对象在赋值、放进容器、删除时的计数变化。 - 想一想:为什么会循环引用的缓存容易把内存吃满。
常见误区
- 以为有垃圾回收就不会泄漏。循环引用、全局缓存照样能漏。
- 以为垃圾回收没有成本。它会带来停顿,只是把成本挪了个地方。
自测三问(点开对答案)
1. 引用计数怎么工作? —— 引用多一个计数加 1,引用没了减 1,减到 0 立即释放;实测 2 → 3 → 2。 2. 引用计数的死穴是什么? —— 循环引用:两个对象互相引用时计数永不为 0,即使删掉外部变量也回收不了,所以要另一套分代回收扫环。 3. 追踪式回收的代价是什么? —— 回收时要停下程序扫一遍,会停顿——所以垃圾回收不是免费的,只是把成本从【想释放】挪到【偶尔卡】。- ☐ 下一节(4.18 对进化的 OOP结构的总结)
相关笔记
- 对进化的 OOP结构的总结 — 三条边界收口
- 编程语言【退化】了吗 — 这笔账怎么算
- ☕ Java基础 · 索引 — JVM 的分代回收
- 🧩 面向对象是怎样工作的 · 索引