Python的垃圾回收机制详解


Posted in Python onAugust 28, 2019

引用计数

在Python源码中,每一个对象都是一个结构体表示,都有一个计数字段。

typedef struct_object {
  int ob_refcnt;
  struct_typeobject *ob_type;
} PyObject;

PyObject是每个对象必有的内容,其中ob_refcnt就是作为引用计数。当一个对象有了新的引用时,它的ob_refcnt就会增加,引用它的对象被删除时则减少。一旦对象的引用计数为0,该对象立即被回收,占用空间就会被释放。

优点

  • 简单易用
  • 实时性好,一旦没有引用就会被立即释放

缺点

  • 需要额外空间去维护引用计数
  • 不能解决对象的循环引用

对象的循环引用
循环引用是指两个对象相互引用且没有外部变量引用其中任何一个,导致引用链形成一个环。

>>> a = {}    # 对象a的引用计数为1
>>> b = {}    # 对象b的引用计数为1
>>> a['b'] = b  # b的引用计数增加1
>>> b['a'] = a  # a的引用计数增加1
>>> del a     # a的引用计数减少1,最后a的引用为1
>>> del b     # b的引用计数减少1,最后b的引用为1

在执行完del操作之后,没有任何引用指向a、b对象,但是由于这两个对象各自包含一个对对方的引用,所以引用计数始终保持在1。

按照引用计数中内存回收的原理,由于a和b的计数不为0,所以在使用引用计数法进行内存管理的时候这两个对象不会被回收,它们会一直驻留在内存中,造成内存泄露。

标记清除

标记清除机制主要用于解决循环引用问题。

标记清除算法是一种基于追踪回收(tracing GC)技术实现的垃圾回收算法。主要分为两个阶段:

  • 标记阶段,GC会将所有的活动对象打上标记
  • 对那些没有打上标记的非活动对象进行回收

区分活动对象与非活动对象

对象之间通过引用即指针连接在一起,构成一个有向图,对象就是这个有向图的节点,而引用关系构成这个有向图的边。从根对象(root object)出发,沿着有向边遍历对象,可达的对象会被标记为活动对象,不可达的对象就是要被清除的非活动对象。

根对象一般是全局变量、调用栈、寄存器等。

适用范围

标记清除算法作为Python辅助的垃圾收集技术,主要处理的是容器对象,因为对于字符串、数值对象等,不可能造成循环引用的问题,Python会使用一个双向链表将这些容器对象组织起来。

对于标记清除算法来说,有一个比较明显的缺点:为了清除非活动对象,需要扫描整个堆内存,哪怕只剩下小部分活动对象也需要扫描所有对象。

分代回收

分代回收是一种以空间换时间的操作方式,建立在标记清除技术的基础之上,也是Python辅助的垃圾收集技术,主要用于处理容器对象。

Python会将内存根据对象的存活时间划分为不同的集合,每个集合称为一个代,主要会被分为3代:年轻代。中年代和老年代,它们会对应3个链表,对应的垃圾收集频率随着对象存活时间的增大而减小。

新创建的对象都会被分配在年轻代,当年轻代链表总数达到上限时,会触发Python的垃圾回收机制,对可回收对象进行回收,而那些不可回收的对象会被移到中年代去。依此类推,老年代对象是存活时间最久的对象,甚至有可能存活在整个系统的生命周期内。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python学习笔记之os模块使用总结
Nov 03 Python
Python多线程编程(一):threading模块综述
Apr 05 Python
python中enumerate函数遍历元素用法分析
Mar 11 Python
通过Python爬虫代理IP快速增加博客阅读量
Dec 14 Python
Django中Forms的使用代码解析
Feb 10 Python
Python实现类似比特币的加密货币区块链的创建与交易实例
Mar 20 Python
Python 网络爬虫--关于简单的模拟登录实例讲解
Jun 01 Python
Spring Cloud Feign高级应用实例详解
Dec 10 Python
python支持多线程的爬虫实例
Dec 21 Python
详解pycharm连接不上mysql数据库的解决办法
Jan 10 Python
基于Tensorflow批量数据的输入实现方式
Feb 05 Python
python for循环赋值问题
Jun 03 Python
Python通过cv2读取多个USB摄像头
Aug 28 #Python
python3.5 cv2 获取视频特定帧生成jpg图片
Aug 28 #Python
Django--权限Permissions的例子
Aug 28 #Python
Python中函数的返回值示例浅析
Aug 28 #Python
django认证系统实现自定义权限管理的方法
Aug 28 #Python
Python中注释(多行注释和单行注释)的用法实例
Aug 28 #Python
对Django的restful用法详解(自带的增删改查)
Aug 28 #Python
You might like
在 PHP 中使用随机数的三个步骤
2006/10/09 PHP
php+javascript的日历控件
2009/11/19 PHP
使用PHPMYADMIN操作mysql数据库添加新用户和数据库的方法
2010/04/02 PHP
PHP跨时区(UTC时间)应用解决方案
2013/01/11 PHP
PHP读取大文件的类SplFileObject使用介绍
2014/04/09 PHP
PHP Opcache安装和配置方法介绍
2015/05/28 PHP
PHP获取客户端及服务器端IP的封装类
2016/07/21 PHP
HTML 自动伸缩的表格Table js实现
2009/04/01 Javascript
ASP.NET jQuery 实例18 通过使用jQuery validation插件校验DropDownList
2012/02/03 Javascript
查找iframe里元素的方法可传参
2013/09/11 Javascript
js模拟点击以提交表单为例兼容主流浏览器
2013/11/29 Javascript
使用JS取得焦点(focus)元素代码
2014/03/22 Javascript
jQuery 中DOM 操作详解
2015/01/13 Javascript
jQuery实现dialog设置focus焦点的方法
2015/06/10 Javascript
jquery实现弹出层登录和全屏层注册特效
2015/08/28 Javascript
js实现页面跳转的五种方法推荐
2016/03/10 Javascript
Bootstrap 表单验证formValidation 实现表单动态验证功能
2017/05/17 Javascript
基于daterangepicker日历插件使用参数注意的问题
2017/08/10 Javascript
解决Jquery下拉框数据动态获取的问题
2018/01/25 jQuery
解决vue 路由变化页面数据不刷新的问题
2018/03/13 Javascript
使用Angular自定义字段校验指令的方法示例
2019/02/01 Javascript
NodeJS实现同步的方法
2019/03/02 NodeJs
vue学习笔记五:在vue项目里面使用引入公共方法详解
2019/04/04 Javascript
JavaScript对象原型链原理解析
2020/01/22 Javascript
vue 使用 canvas 实现手写电子签名
2020/03/06 Javascript
微信小程序实现加入购物车滑动轨迹
2020/11/18 Javascript
对python中for、if、while的区别与比较方法
2018/06/25 Python
python3利用venv配置虚拟环境及过程中的小问题小结
2018/08/01 Python
Flask Web开发入门之文件上传(八)
2018/08/17 Python
python shapely.geometry.polygon任意两个四边形的IOU计算实例
2020/04/12 Python
HTML5去掉输入框type为number时的上下箭头的实现方法
2020/01/03 HTML / CSS
什么是静态路由,其特点是什么?什么是动态路由,其特点是什么?
2013/07/26 面试题
大学自我鉴定范文
2013/12/26 职场文书
村官2015年度工作总结
2015/10/14 职场文书
2016计算机专业毕业生自荐信
2016/01/28 职场文书
Python装饰器的练习题
2021/11/23 Python