PEP 683 改变了 Python 原有引用计数的一些逻辑,下面简单介绍一下。
CPython 的“引用计数可变性”已经成为并发、性能和未来发展的系统性障碍。
引用对象导致 “逻辑不可变对象” ≠ “物理不可变对象”
在 Cpython 中
NoneTrue/Falseint,str,list等内建对象
在运行时引用计数会频繁变动,这意味着内存内容在不断被写入,在底层并非真正的 immutable
引用计数写操作降低并发性能
CPU Cache Line 失效
Py_INCREF / Py_DECREF会写内存 -> cache line invalidation在多线程 / 多核环境中,同一个全局对象被频繁引用,会造成严重的缓存抖动
fork + Copy-on-Write 失效
父子进程共享内存页
只要引用计数一变 -> 页面被写 -> 触发 COW
只是“多拿了个引用”,却导致整页内存复制
为 free-threading (no GIL) 清扫道路
CPython 的引用计数本质是全局共享的可变状态,在无 GIL 下会产生高频数据竞争。 要么给 refcount 加锁(性能太差),要么让一部分的 refcount 不再变化。
该提案将“对象生命周期模型”划分成了两类对象
| 对象类型 | 生命周期 | refcount 行为 |
|---|---|---|
| 普通对象 | 动态 | 正常增减 |
| 不朽对象 | 解释器级 | 固定,不参与 gc |
这让后续优化和推理都更清晰,也会导致 sys.getrefcount() 不再具有语义价值,测试默认返回 2 的 23 次方减 1。