python垃圾回收算法
标准python垃圾回收器由两部分组成,即引用计数回收器和分代垃圾回收器(即python包中的gc module)。其中,引用计数模块不能被禁用,而GC模块可以被禁用。
引用计数算法
python中每个变量都是对象,每个对象核心都包含一个结构体PyObject:
typedef struct_object {
int ob_refcnt;
struct_typeobject *ob_type;
} PyObject;
其中ob_refcnt变量记录了这个对象被引用的数量,当这个对象的引用被赋值给另一个变量或者这个引用被删除(如del a)。那么ob_refcnt就会随之加1或者减1。引用计数增加的场景有:
- 赋值操作
- 参数传递
- 添加object到list末尾
如果某个对象的引用计数为0,那么python会立马调用函数释放内存空间,此时可能导致这个对象引用的其他对象引用计数也为0,因此一个对象消亡可能引起一连串对象内存空间被释放。
一般说来,全局变量(定义在函数,类和代码块之外的变量)随python进程退出而释放,因此引用计数永远不会减为0。局部变量(定义在函数,类和代码块之内的变量)反之。
引用计数算法原理简单明了,但是存在循环引用,线程锁和内存性能开销等问题。
分代垃圾回收算法
引用计数算法最大问题就是循环引用,这种情况下循环引用的每个对象的引用计数最终都不会归零,如下图所示:

因此,python在gc module实现了循环检测算法来解决这个问题。循环引用只可能发生在容器对象之间,因此,GC循环检测也只对容器对象使用。对于只包含常量的容器(如包含常量的tuple),GC也会把这部分排除掉。
GC将容器对象分为3代,定期清理每代的垃圾对象。新分配的对象总是在第0代,如果经历过一次垃圾回收依然存活则移入下一代。新生代的回收频率比老年代高,大部分新对象很快就会释放,因此生命周期都只是停留在第0代。这种分代回收方式可以提高GC性能,减少停顿时间。
GC进行时需要停止程序的执行以免引用关系改变。
为了确定何时可以执行垃圾回收,GC每一代维护都会count和threshold两个变量,其中count=上一次垃圾回收后分配的新对象-上一次垃圾回收后已经消亡对象(因为引用计数为0而被释放),每次对象创建时候都会比较count和threshold大小,如果count>threshold,python就会启动垃圾回收进程。
以下详细说明CPython循环检测的原理,CPython维护两个双向链表:一个是需要检测的对象关系链表(objects list),一个是存放无法访达的对象链表(Unreachable list)。
- 如下图所示,假设现在清理的是第0代的垃圾对象。左边的需要扫描的对象列表中link4是一个循环引用。varA是link1的外部引用,可能是其他代的对象。每个对象除了有一个引用计数变量ref count外,还维护一个gc_ref变量,初始时ref count=gc_ref.
 - GC遍历objects list每个对象,将这个对象所引用的其他对象的gc_ref减1。
 - GC将步骤2中gc_ref=0的对象挪到Unreachable list中,下图表示将已经处理的link3和link4移到Unreachable list,但是还没有处理link1和link2.
 - 当GC扫描link1时候,发现gc_ref=1,是可以访达的,那么GC就会循环遍历link1引用的对象,将其标记为可以访达。因为link3经过此轮后标记为可以访达,那么就会将其从Unreachable list移到之前的list中。
 - GC扫描完所有的对象后,就会启动垃圾回收进程,将Unreachable list中的对象清理掉。
为了性能考虑,我们应该尽量避免循环引用,可以使用weakrefmodule,weakref.ref不会增加对象的引用计数并且对象被回收后返回None。此外,可以使用gc.disable()手动关闭GC垃圾回收,这在某些特殊情况下有帮助。
参考资料
[1] Garbage collection in Python: things you need to know
[2] Python垃圾回收机制
[3] The Garbage Collector
[4] Python垃圾回收(GC)三层心法,你了解到第几层
python垃圾回收算法的更多相关文章
- 《垃圾回收的算法与实现》——Python垃圾回收
Python垃圾回收 python采用引用计数法进行垃圾回收 Python内存分配 python在分配内存空间时,在malloc之上堆放了3个独立的分层. python内存分配时主要由arena.po ...
- Python垃圾回收机制
引用计数Python默认的垃圾收集机制是“引用计数”,每个对象维护了一个ob_ref字段.它的优点是机制简单,当新的引用指向该对象时,引用计数 引用计数 Python默认的垃圾收集机制是“引用计数”, ...
- 深入理解java虚拟机【垃圾回收算法】
Java虚拟机的内存区域中,程序计数器.虚拟机栈和本地方法栈三个区域是线程私有的,随线程生而生,随线程灭而灭:栈中的栈帧随着方法的进入和退出而进行入栈和出栈操作,每个栈帧中分配多少内存基本上是在类结构 ...
- (转)《深入理解java虚拟机》学习笔记3——垃圾回收算法
Java虚拟机的内存区域中,程序计数器.虚拟机栈和本地方法栈三个区域是线程私有的,随线程生而生,随线程灭而灭:栈中的栈帧随着方法的进入和退出而进行入栈和出栈操作,每个栈帧中分配多少内存基本上是在类结构 ...
- C/C++中几种经典的垃圾回收算法
1.引用计数算法 引用计数(Reference Counting)算法是每个对象计算指向它的指针的数量,当有一个指针指向自己时计数值加1:当删除一个指向自己的指针时,计数值减1,如果计数值减为0,说明 ...
- 深入理解java垃圾回收算法
Java虚拟机的内存区域中,程序计数器.虚拟机栈和本地方法栈三个区域是线程私有的,随线程生而生,随线程灭而灭:栈中的栈帧随着方法的进入和退出而进行入栈和出栈操作,每个栈帧中分配多少内存基本上是在类结构 ...
- Python垃圾回收机制--完美讲解!
转自: http://www.jianshu.com/p/1e375fb40506 先来个概述,第二部分的画述才是厉害的. Garbage collection(GC) 现在的高级语言如java,c# ...
- C++ 几种经典的垃圾回收算法
之前遇到了一篇好文(https://blog.csdn.net/wallwind/article/details/6889917)准备学习一下的,课程繁忙就忘记了,今日得闲,特来补一下. 自己写一遍加 ...
- JVM垃圾回收算法及回收器详解
引言 本文主要讲述JVM中几种常见的垃圾回收算法和相关的垃圾回收器,以及常见的和GC相关的性能调优参数. GC Roots 我们先来了解一下在Java中是如何判断一个对象的生死的,有些语言比如Pyth ...
随机推荐
- SQLSever: 怎样在select中的每一行产生不同的随机数?
select 的随机函数有点假, 或许是由于它是基于时间来的吧, 同一select中由于时间无法错开导致产生的随机数都是一样的. 怎样做到让不同的行拥有不同的随机数呢? 以下以产生某个月的随机日期来演 ...
- 日期格式,Popup的使用方法,RenderTransform与LayoutTransform的区别
1.画个笑脸给大家娱乐一下: <Canvas Width="200" Height="180" VerticalAlignment="Cente ...
- 37.创建自定义的指令的限制使用 通过restrict 设置
转自:https://www.cnblogs.com/best/tag/Angular/ 1. 元素名 <runoob-directive></runoob-directive> ...
- Mysql优化ibdata1大小
在MySQL数据库中,如果不指定innodb_file_per_table参数来单独存在每个表的数据,MySQL的数据都会存放在ibdata1文件.mysql ibdata1存放数据,索引等,是MYS ...
- ARM嵌入式复习
第一章 1.嵌入式系统 “以应用为中心,以计算机技术为基础,软硬件可裁剪,适用于应用系统对功能,可靠性,成本,体积,功耗要求严格的专用计算机系统” 根据应用的要求,沿着“体积小,低功耗,高可靠”方向发 ...
- 【转】android新组件RecyclerView使用介绍和进阶使用,替用Gallery
简介: RecyclerView是support-v7包中的新组件,是一个强大的滑动组件,与经典的ListView相比,同样拥有item回收复用的功能,但是直接把viewholder的实现封装起来,用 ...
- 如何配置MySQL?(三)
要进行mysql配置,首先要找到mysql的配置向导文件,这个配置向导文件就在我们安装目录下的一个bin的子目录下. 刚才我们是选择典型安装MySQL,一般windows是默认存储在C:\Progra ...
- js thousand separator and change td content
js thousand seprator and change TD content // integer function addCommas(n){ })/; return String(n).r ...
- GoldenGate 性能优化方法
从根本上讲,OGG复制性能和要复制的表是否存在主键和唯一索引有很大关系,所以从应用系统开发商对表结构的规范更为有效.OGG调优通常采用拆分进行的方式,拆分方法如下所述. Extract拆分方法 1) ...
- CF718C Sasha and Array(线段树维护矩阵)
题解 (不会矩阵加速的先去学矩阵加速) 反正我想不到线段树维护矩阵.我太菜了. 我们在线段树上维护一个区间的斐波那契的列矩阵的和. 然后询问时提取每个符合题意列矩阵的答案项(不是列矩阵存了两项吗,一个 ...