内存管理
Python引入了内存池机制, 用于管理对小块内存的申请和释放。
如果需要分配的空间大于SMALL_REQUEST_THRESHOLD bytes(定义在Objects/obmalloc.c中,我的2.7.11版本是512),则直接使用系统的内存分配接口申请内存空间,主要是C中的malloc;否则从内存池中申请内存空间,涉及到的有block,pool和arena。在内存释放的时候,当对象的应用计数为0时,自动调用其析构函数,从内存池中申请来的内存会被归还到内存池中。
垃圾回收
Python 中垃圾回收机制: 引用计数(主要), 标记清除, 分代收集(辅助)
引用计数
当一个对象的引用被创建或者复制时,对象的引用计数加1;当一个对象的引用被销毁时,对象的引用计数减1;当对象的引用计数减少为0时,就意味着对象已经没有被任何人使用了,可以将其所占用的内存释放了。
引用计数的优点在于“实时性”,缺点在于维护引用计数时所带来的效率问题和循环引用问题。
标记清除
主要是为了解决循环引用问题。首先观察到循环引用只能被容器对象创造。容器对象是可以包含其他对象的引用的对象,例如列表,字典,实例,类和元祖,而整数和字符串不是容器对象。
标记清除的方法使用双向链表来记录所有的容器对象,在容器对象中添加两个指针,以方便容器对象的快速插入和删除,且不需要额外的内存空间分配。同时,需要在容器对象中新增字段gc_refs,通过以下步骤找到循环引用:
- 对于每个容器对象,设置gc_refs的值为对象的引用计数。
- 对于每个容器对象,找到它引用的其它容器对象,并将它们的gc_refs值减1。
- 所有gc_refs大于1的容器对象是被容器对象集合外的对象所引用的。这些对象不能释放,所以把这些对象放到另外一个集合内。
- 被移走的对象所引用的对象也是不能被释放的,所以将他们和他们能访问到的对象都从目前的集合中移走。
- 目前集合中剩下的对象是仅被该集合中对象引用的,他们无法被python取到,也就是来及,现在可以去释放这些对象。
分代收集
分代收集用来提升垃圾回收的效率。这一策略的基本假设是:存活时间越久的对象,越不可能是垃圾。
Python将所有对象分为0,1,2三代。所有新建对象都是0代对象。当某一代对象经历过垃圾回收后依然存活,那么它就被归入下一代对象。垃圾回收启动时,一定会扫描0代对象,如果0代经过一定次数垃圾回收,那么就启动对0代和1代的扫描清理。当1代也经历了一定次数的垃圾回收后,那么会启动对0,1,2,即对所有对象进行扫描。通过gc.get_threshold()方法可以看到当前的默认分代收集配置,通过gc.set_threshold(700, 10, 5)来对这一配置进行调整。