python中的垃圾回收(GC)机制


Posted in Python onSeptember 21, 2020

一、引用计数

Python 垃圾回收以引用计数为主,分代回收为辅。引用计数法的原理是每个对象维护一个ob_refcnt,用来记录对象被引用的次数,也就是用来追踪有多少个引用指向了对象,当发生以下四种情况的时候,对象的引用计数+1:

  • 对象被创建,比如:a = 14
  • 对象被引用,比如: b = a
  • 对象被作为参数,传给函数,比如:func(a)
  • 对象作为容器中的一个元素,比如:List = {a, ”a” , ”b”, 2}

与上述情况相对应,当发生以下四种情况时,对象的引用计数-1:

对象的别名被显式销毁,比如:del a
对象的别名被赋予新的对象,比如:a = 26
对象离开它的作用域,比如 func() 执行完毕时,函数里面的所有局部变量的引用计数都会减 1
将元素从容器中删除,或者容器被销毁
当对象的引用计数为 0 时,它将被 Python 虚拟机回收。

在 Python 中一切皆对象,它们的核心是 Py_Object 结构体,所有 Python 对象的头部都包含该结构:

// object.h
#define PyObject_HEAD   
 _PyObject_HEAD_EXTRA  
 Py_ssize_t ob_refcnt;  
 struct _typeobject *ob_type;
​
typedef struct _object {
 PyObject_HEAD
} PyObject;

比如 int 类型的定义如下:

// intobj.h
typedef struct {
 PyObject_HEAD
 long ob_ival;
} PyIntObject;

简而言之,PyObject 是每个对象必有的内容,其中 ob_refcnt 是对象的引用计数。对象有新的引用时,它的 ob_refcnt 会增加;当对象的引用被删除时,ob_refcnt 会减少。当引用计数为 0 时,对象的生命周期就结束了。

// object.h
#define Py_INCREF(op) (    
 _Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA 
 ((PyObject*)(op))->ob_refcnt++)
​
#define Py_DECREF(op)     
 do {      
 if (_Py_DEC_REFTOTAL _Py_REF_DEBUG_COMMA 
 --((PyObject*)(op))->ob_refcnt != 0)  
  _Py_CHECK_REFCNT(op)   
 else      
 _Py_Dealloc((PyObject *)(op));   
 } while (0)

引用计数有很明显的优点:

  • 高效
  • 运行期没有停顿,即实时性:对象一旦没有引用,将直接被释放。实时性还带来一个好处是:处理回收内存的时间分摊到了平时
  • 对象有确定的生命周期
  • 易于实现

原始的引用计数法也有明显的缺点:

  • 维护引用计数消耗资源,维护引用计数的次数和引用赋值成正比
  • 无法解决循环引用的问题

比如:

list1 = []
list2 = []
list1.append(list2)
list2.append(list1)

为了解决这两个致命弱点,Python 又引入了以下两种 GC 机制。

二、标记-清除

『标记-清除(Mark-Sweep)』算法是一种基于追踪回收(tracing GC)技术实现的垃圾回收算法。它分为两个阶段:第一阶段是标记阶段,GC 会给所有『活动对象』打上标记;第二阶段是回收没有标记的『非活动对象』。那么 GC 如何判断哪些是活动对象、哪些是非活动对象呢?

对象之间通过引用(指针)连在一起,构成一个有向图。对象是有向图的顶点,引用关系是有向图的弧。从根对象(root object)出发,遍历有向图,将可达的(reachable)对象标记为活动对象,不可达的对象就是要被清除的非活动对象。根对象是全局变量、调用栈、寄存器。

python中的垃圾回收(GC)机制

在上图中,把小黑圈视为全局变量,也就是把它作为 root object,从小黑圈出发,对象 1 可直达,那么它将被标记,对象 2、3 可间接到达,也会被标记,而 4 和 5 不可达,因此 1、2、3 是活动对象,4 和 5 是非活动对象,会被 GC 回收。

标记清除算法作为 Python 的辅助垃圾回收技术,主要用于处理容器对象,比如 list、dict、tuple、instance 等,因为字符串、数值等原子类型的对象不可能造成循环引用问题。Python 使用双向链表将容器对象组织起来。不过这种简单粗暴的标记清除算法也有明显的缺点:清除非活动对象前,必须顺序扫描整个堆内存,哪怕只剩下小部分非活动对象,也要扫描所有对象。

三,分代回收

分代回收是一种以空间换时间的操作方式,Python 将内存根据对象的存活时间划分为不同的集合,每个集合称为一个代,Python 将内存分为了 3 代,分别为年轻代(第 0 代)、中年代(第 1 代)、老年代(第 2 代),它们对应是 3 个链表,垃圾回收频率随着对象存活时间的增大而减小。新创建的对象都会被分配到年轻代,当年轻代链表的节点总数达到上限时,Python 垃圾收集机制就会被触发,把可以被回收的对象回收掉,而不能被回收的对象会被移到中年代去,依此类推,老年代中的对象是存活时间最久的对象,甚至存活于整个系统的生命周期内。分代回收建立在标记清除的基础之上,分代回收同样作为 Python 处理容器对象的辅助垃圾回收技术。

以上就是python中的GC机制的详细内容,更多关于python GC的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
python模拟鼠标拖动操作的方法
Mar 11 Python
在Python的web框架中编写创建日志的程序的教程
Apr 30 Python
python使用MySQLdb访问mysql数据库的方法
Aug 03 Python
Python数据可视化编程通过Matplotlib创建散点图代码示例
Dec 09 Python
python TCP Socket的粘包和分包的处理详解
Feb 09 Python
如何在python字符串中输入纯粹的{}
Aug 22 Python
使用python打印十行杨辉三角过程详解
Jul 10 Python
python图形绘制奥运五环实例讲解
Sep 14 Python
Python3运算符常见用法分析
Feb 14 Python
django模板获取list中指定索引的值方式
May 14 Python
解决keras加入lambda层时shape的问题
Jun 11 Python
Python词云的正确实现方法实例
May 08 Python
如何在Python3中使用telnetlib模块连接网络设备
Sep 21 #Python
总结Pyinstaller的坑及终极解决方法(小结)
Sep 21 #Python
python生成xml时规定dtd实例方法
Sep 21 #Python
Python中的特殊方法以及应用详解
Sep 20 #Python
matplotlib 三维图表绘制方法简介
Sep 20 #Python
Python三维绘图之Matplotlib库的使用方法
Sep 20 #Python
scrapy利用selenium爬取豆瓣阅读的全步骤
Sep 20 #Python
You might like
比较简单实用的PHP无限分类源码分享(思路不错)
2011/10/13 PHP
php curl常见错误:SSL错误、bool(false)
2011/12/28 PHP
php实现加减法验证码代码
2014/02/14 PHP
Prototype使用指南之range.js
2007/01/10 Javascript
ajax更新数据后,jquery、jq失效问题
2011/03/16 Javascript
js判断IE浏览器版本过低示例代码
2013/11/22 Javascript
JavaScript中property和attribute的区别详细介绍
2015/03/03 Javascript
JavaScript中判断函数、变量是否存在
2015/06/10 Javascript
js实现仿MSN带关闭功能的右下角弹窗代码
2015/09/04 Javascript
js实现超酷的照片墙展示效果图附源码下载
2015/10/08 Javascript
jQuery+正则+文本框只能输入数字的实现方法
2016/10/07 Javascript
前端js实现文件的断点续传 后端PHP文件接收
2016/10/14 Javascript
原生JS中slice()方法和splice()区别
2017/03/06 Javascript
javascript 作用于作用域链的详解
2017/09/27 Javascript
详解如何用模块化的方式写vuejs
2017/12/16 Javascript
看看“疫苗查询”小程序有温度的代码
2018/07/31 Javascript
详解50行代码,Node爬虫练手项目
2019/04/22 Javascript
vue实现抖音时间转盘
2019/09/08 Javascript
Electron 打包问题:electron-builder 下载各种依赖出错(推荐)
2020/07/09 Javascript
[01:20:38]完美世界DOTA2联赛 GXR vs IO 第一场 11.07
2020/11/09 DOTA
SublimeText 2编译python出错的解决方法(The system cannot find the file specified)
2013/11/27 Python
python中使用xlrd、xlwt操作excel表格详解
2015/01/29 Python
Python中的rfind()方法使用详解
2015/05/19 Python
Python中flatten( )函数及函数用法详解
2018/11/02 Python
Python基于OpenCV实现人脸检测并保存
2019/07/23 Python
python函数参数(必须参数、可变参数、关键字参数)
2019/08/16 Python
浅谈Python3中print函数的换行
2020/08/05 Python
Python jieba库分词模式实例用法
2021/01/13 Python
美国运动鞋和运动服零售商:Footaction
2017/04/07 全球购物
德国著名廉价网上药店:Shop-Apotheke
2017/07/23 全球购物
英国健身超市:Fitness Superstore
2019/06/17 全球购物
保险公司早会主持词
2014/03/22 职场文书
2016新年慰问信范文
2015/03/25 职场文书
结婚纪念日感言
2015/08/01 职场文书
幼儿园中班教学反思
2016/03/03 职场文书
教你如何使用Python下载B站视频的详细教程
2021/04/29 Python