原文链接:
Python 中有两种内存管理机制共存:
- 引用计数:当一个对象的引用为0时,对象被删除(但是无法处理循环引用)
- 垃圾回收:
在Python中, 所有能够引用其他对象的对象都被称为容器(container). 因此只有容器之间才可能形成循环引用. Python的垃圾回收机制利用了这个特点来寻找需要被释放的对象. 为了记录下所有的容器对象, Python将每一个 容器都链到了一个双向链表中, 之所以使用双向链表是为了方便快速的在容器集合中插入和删除对象. 有了这个 维护了所有容器对象的双向链表以后, Python在垃圾回收时使用如下步骤来寻找需要释放的对象:
- 对于每一个容器对象, 设置一个
gc_refs
值, 并将其初始化为该对象的引用计数值. - 对于每一个容器对象, 找到所有其引用的对象, 将被引用对象的
gc_refs
值减1. - 执行完步骤2以后所有
gc_refs
值还大于0的对象都被非容器对象引用着, 至少存在一个非循环引用. 因此 不能释放这些对象, 将他们放入另一个集合. - 在步骤3中不能被释放的对象, 如果他们引用着某个对象, 被引用的对象也是不能被释放的, 因此将这些 对象也放入另一个集合中.
- 此时还剩下的对象都是无法到达的对象. 现在可以释放这些对象了.
值得注意的是, 如果一个Python对象含有__del__
这个方法, Python的垃圾回收机制即使发现该对象不可到达 也不会释放他. 原因是__del__
这个方式是当一个Python对象引用计数为0即将被删除前调用用来做清理工作的. 由于垃圾回收找到的需要释放的对象中往往存在循环引用的情况, 对于循环引用的对象a和b, 应该先调用哪 一个对象的__del__
是无法决定的, 因此Python垃圾回收机制就放弃释放这些对象, 转而将这些对象保存起来, 通过gc.garbage这个变量访问. 程序员可以通过gc.garbage
手动释放对象, 但是更好的方法是避免在代码中定义__del__
这个方法.