大师兄的Python源码学习笔记(五十一): Python的内存管理机制(六)
大师兄的Python源码学习笔记(五十三): Python的内存管理机制(八)
四、循环引用的垃圾收集
1. 引用计数与垃圾收集
- Python在语言层实现了内存的动态管理,但与Java不同的是,在Python中大多数对象的生命周期都是通过对象的引用计数来管理的。
- 引用计数是一种最直观、最简单的垃圾收集技术,他的优点是实时性:任何内存,一旦没有指向它的引用,则立即回收;而其它垃圾收集技术必须在某种特定条件下,如内存分配失败才能进行无效内存的回收。
- 同样,引用计数的软肋也很明显,就是必须在每次分配和释放内存的时候加入管理引用计数的动作来进行内存的分配与释放,导致的额外操作与引用赋值的次数成正比;这与其它主流垃圾回收技术,比如Mark-Sweep和Stop-Copy,引用计数在内存分配和释放上的效率较低。
- 因此,为了与引用计数机制搭配,在内存的分配和释放上获得最高的效率,Python设计了大量的内存池机制,比如之前写到的PyIntObject对象的内存池就是为了弥补引用计数机制的这个软肋。
- 除了执行效率之外,引用计数技术还有存在一个致命弱点,就是循环引用:
- 在循环引用的情况下,对象占用的内存永远不会被回收,造成内存泄露。
- 为此,Python引入了主流垃圾手机技术中的标记——清除和分代收集两种技术来填补这个漏洞。
2. 三色标记模型
- 垃圾收集机制一般分为两个阶段:垃圾检测和垃圾回收。
- 垃圾检测:是从所有已分配的内存中去别处可以回收的内存和不可回收的内存。
- 垃圾回收:是使系统重新掌握在垃圾检测阶段所标识出来的可回收内存块。
- 而Python的垃圾收集是基于三色标机模型完成的,其简要工作过程如下:
- 寻找根对象(root object)的集合:
- 所谓根对象就是一些全局引用和函数栈中的引用。
- 这些引用所用的对象是不可被删除的。
- 而根对象集合也是垃圾检测动作的起点。
- 垃圾检测阶段:
- 从根对象集合出发,沿着根对象集合的每一个引用,如果能到达某个对象A,则A称为reachable,reachable对象不可被删除。
- 垃圾回收阶段:
- 垃圾检测阶段结束后,所有对象分为了reachable和unreachable两部分。
- 所有reachable对象必须保留,而所有unreachable对象将被回收。
- 在垃圾收集动作被激活前,系统中所分配的所有对象和对象之间的引用组成一张有向图,其中对象是图中的节点,而对象间的引用是图的边。
- 我们在这个有向图的基础上建立了一个三色标注模型,更形象地展示垃圾收集的整个动作。
- 当垃圾收集开始时,我们假设系统中的所有对象都是不可达的,对应地图上的白色节点。
- 随后,从垃圾收集的动作开始,沿着始于根对象集合中的某个对象的引用链,在某个个时刻到达了对象A,那么将A标记会灰色表示对象可达,但是其所包含的引用还没有检查。
- 当检查了对象A中所包含的所有引用之后,A对象就被标记为黑色。
- 这时,A对象中所引用的对象责备标记为了灰色。
- 加入我们从根对象集合出发,采用广度搜索的策略,灰色节点对象集合就如同一个波的阵面一样,不断向外扩散。
- 随着所有的灰色节点都变为了黑色节点,也就意味着垃圾检测阶段结束了。
网友评论