python的回收机制_Python的垃圾回收机制深入分析
一、概述:
Python的GC模块主要运用了“引用计数”(reference counting)来跟踪和回收垃圾。在引用计数的基础上,还可以通过“标记-清除”(mark and sweep)解决容器对象可能产生的循环引用的问题。通过“分代回收”(generation collection)以空间换取时间来进一步提高垃圾回收的效率。
二、引用计数
在Python中,大多数对象的生命周期都是通过对象的引用计数来管理的。从广义上来讲,引用计数也是一种垃圾收集机制,而且也是一种最直观,最简单的垃圾收集技术。
原理:当一个对象的引用被创建或者复制时,对象的引用计数加1;当一个对象的引用被销毁时,对象的引用计数减1;当对象的引用计数减少为0时,就意味着对象已经没有被任何人使用了,可以将其所占用的内存释放了。
虽然引用计数必须在每次分配和释放内存的时候加入管理引用计数的动作,然而与其他主流的垃圾收集技术相比,引用计数有一个最大的有点,即“实时性”,任何内存,一旦没有指向它的引用,就会立即被回收。而其他的垃圾收集计数必须在某种特殊条件下(比如内存分配失败)才能进行无效内存的回收。
引用计数机制执行效率问题:引用计数机制所带来的维护引用计数的额外操作与Python运行中所进行的内存分配和释放,引用赋值的次数是成正比的。而这点相比其他主流的垃圾回收机制,比如“标记-清除”,“停止-复制”,是一个弱点,因为这些技术所带来的额外操作基本上只是与待回收的内存数量有关。
如果说执行效率还仅仅是引用计数机制的一个软肋的话,那么很不幸,引用计数机制还存在着一个致命的弱点,正是由于这个弱点,使得侠义的垃圾收集从来没有将引用计数包含在内,能引发出这个致命的弱点就是循环引用(也称交叉引用)。
问题说明:
循环引用可以使一组对象的引用计数不为0,然而这些对象实际上并没有被任何外部对象所引用,它们之间只是相互引用。这意味着不会再有人使用这组对象,应该回收这组对象所占用的内存空间,然后由于相互引用的存在,每一个对象的引用计数都不为0,因此这些对象所占用的内存永远不会被释放。比如:
a = []
b = []
a.append(b)
b.append(a)
print a
[[[…]]]
print b
[[[…]]]
这一点是致命的,这与手动进行内存管理所产生的内存泄露毫无区别。
要解决这个问题,Python引入了其他的垃圾收集机制来弥补引用计数的缺陷:“标记-清除”,“分代回收”两种收集技术。
三、标记-清除
“标记-清除”是为了解决循环引用的问题。可以包含其他对象引用的容器对象(比如:list,set,dict,class,instance)都可能产生循环引用。
我们必须承认一个事实,如果两个对象的引用计数都为1,但是仅仅存在他们之间的循环引用,那么这两个对象都是需要被回收的,也就是说,它们的引用计数虽然表现为非0,但实际上有效的引用计数为0。我们必须先将循环引用摘掉,那么这两个对象的有效计数就现身了。假设两个对象为A、B,我们从A出发,因为它有一个对B的引用,则将B的引用计数减1;然后顺着引用达到B,因为B有一个对A的引用,同样将A的引用减1,这样,就完成了循环引用对象间环摘除。
但是这样就有一个问题,假设对象A有一个对象引用C,而C没有引用A,如果将C计数引用减1,而最后A并没有被回收,显然,我们错误的将C的引用计数减1,这将导致在未来的某个时刻出现一个对C的悬空引用。这就要求我们必须在A没有被删除的情况下复原C的引用计数,如果采用这样的方案,那么维护引用计数的复杂度将成倍增加。
原理:“标记-清除”采用了更好的做法,我们并不改动真实的引用计数,而是将集合中对象的引用计数复制一份副本,改动该对象引用的副本。对于副本做任何的改动,都不会影响到对象生命走起的维护。
这个计数副本的唯一作用是寻找root object集合(该集合中的对象是不能被回收的)。当成功寻找到root object集合之后,首先将现在的内存链表一分为二,一条链表中维护root object集合,成为root链表,而另外一条链表中维护剩下的对象,成为unreachable链表。之所以要剖成两个链表,是基于这样的一种考虑:现在的unreachable可能存在被root链表中的对象,直接或间接引用的对象,这些对象是不能被回收的,一旦在标记的过程中,发现这样的对象,就将其从unreachable链表中移到root链表中;当完成标记后,unreachable链表中剩下的所有对象就是名副其实的垃圾对象了,接下来的垃圾回收只需限制在unreachable链表中即可。
四、分代回收
背景:分代的垃圾收集技术是在上个世纪80年代初发展起来的一种垃圾收集机制,一系列的研究表明:无论使用何种语言开发,无论开发的是何种类型,何种规模的程序,都存在这样一点相同之处。即:一定比例的内存块的生存周期都比较短,通常是几百万条机器指令的时间,而剩下的内存块,起生存周期比较长,甚至会从程序开始一直持续到程序结束。
从前面“标记-清除”这样的垃圾收集机制来看,这种垃圾收集机制所带来的额外操作实际上与系统中总的内存块的数量是相关的,当需要回收的内存块越多时,垃圾检测带来的额外操作就越多,而垃圾回收带来的额外操作就越少;反之,当需回收的内存块越少时,垃圾检测就将比垃圾回收带来更少的额外操作。为了提高垃圾收集的效率,采用“空间换时间的策略”。
原理:将系统中的所有内存块根据其存活时间划分为不同的集合,每一个集合就成为一个“代”,垃圾收集的频率随着“代”的存活时间的增大而减小。也就是说,活得越长的对象,就越不可能是垃圾,就应该减少对它的垃圾收集频率。那么如何来衡量这个存活时间:通常是利用几次垃圾收集动作来衡量,如果一个对象经过的垃圾收集次数越多,可以得出:该对象存活时间就越长。
举例说明:
当某些内存块M经过了3次垃圾收集的清洗之后还存活时,我们就将内存块M划到一个集合A中去,而新分配的内存都划分到集合B中去。当垃圾收集开始工作时,大多数情况都只对集合B进行垃圾回收,而对集合A进行垃圾回收要隔相当长一段时间后才进行,这就使得垃圾收集机制需要处理的内存少了,效率自然就提高了。在这个过程中,集合B中的某些内存块由于存活时间长而会被转移到集合A中,当然,集合A中实际上也存在一些垃圾,这些垃圾的回收会因为这种分代的机制而被延迟。
在Python中,总共有3“代”,也就是Python实际上维护了3条链表。具体可以查看Python源码详细了解。
python的回收机制_Python的垃圾回收机制深入分析相关推荐
- 关于python的垃圾回收机制_Python的垃圾回收机制
知识点的铺垫 对象和引用 python作为一门动态语言,一个简单的赋值语句也是很值得研究的,重要特点就是引用对象分离. a = 1 其中整数1是一个对象,而a是一个引用.利用赋值语句,引用a指向对象1 ...
- python的super super easy教程 | 垃圾回收 引用计数 深拷贝和浅拷贝
input最好是放在函数外面range(i)表示从0到(i-1)函数的作用:接收一个参数 返回一个参数python的内存管理 (常见的面试题)python的内存机制:以引用计数为主,分代回收,标记清除 ...
- java 垃圾回收机制_Java的垃圾回收机制
前言 在C++语言中, 程序员必须小心谨慎的处理每一项内存分配, 且内存使用完后必须手动释放曾经占用的内存空间.当内存释放不够完全时, 即存在分配但永不释放的内存块, 就会引起"内存泄漏&q ...
- 垃圾回收机制和JVM垃圾回收常见算法
垃圾回收机制和JVM垃圾回收常见算法 垃圾回收的好处和特点: 好处: 1. 提高编程效率: 2. 垃圾回收机制保护程序的完整性. 特点: 1. 只能回收无用对象的内存空间,对其他物理资源无能为力: 2 ...
- c++对象回收问题_从垃圾回收解开Golang内存管理的面纱之三垃圾回收
四.垃圾回收 终于说到垃圾回收了,我的初衷就是要搞明白垃圾回收的算法,谁知道衍生出来那么多东西,哈哈. 5.1 常见垃圾回收策略 所谓垃圾回收,即为释放我们不再使用的对象的内存,话不多说,我们一一分析 ...
- 垃圾回收分类系统、垃圾回收高保真原型设计 、垃圾分类后台管理系统、垃圾回收分类平台、垃圾回收分类、智慧管理系统、订单管理、财务管理、系统管理、库存管理、设备管理、Axure原型、rp原型
Axure高保真web端后台管理系统.垃圾回收分类系统.垃圾回收高保真原型设计 .垃圾分类后台管理系统.垃圾回收分类平台.垃圾回收分类.智慧管理系统.订单管理.财务管理.系统管理.库存管理.设备管理 ...
- JVM垃圾回收系列--内存模型/垃圾回收流程
原文网址:JVM垃圾回收系列--内存模型/垃圾回收流程_IT利刃出鞘的博客-CSDN博客 简介 本文介绍Java各个代的关系(内存模型)及垃圾收集流程. 内存模型 JDK8的内存模型 在Java中所有 ...
- python解析原理_Python语法垃圾回收机制原理解析
一 引入 解释器在执行到定义变量的语法时,会申请内存空间来存放变量的值,而内存的容量是有限的,这就涉及到变量值所占用内存空间的回收问题,当一个变量值没有用了(简称垃圾)就应该将其占用的内存给回收掉,那 ...
- python 类定义 垃圾_什么是python对象摧毁?python中的对象摧毁(垃圾回收)机制是什么?...
在这篇文章之中我们来了解一下python对象摧毁(垃圾回收),对于刚刚接触到python这一编程语言的朋友来说,对于python对象摧毁(垃圾回收)的了解应该比较少,并且不清楚关于python垃圾回收 ...
最新文章
- 文本分类的基本思想和朴素贝叶斯算法原理
- 容灾与备份究竟有什么区别?
- boost::mpl模块实现lower_bound相关的测试程序
- ocelot简单入门
- hexo 环境变量_Hexo自动部署
- java并发包作者lee_Java的一些并发包
- python for android 安装配置_mac appium for android 环境搭建 (appium python pycharm)
- python中文版软件下载-Python中文版下载_PyCharm官方最新版下载_3DM单机
- 针对2020年市面上短信供应商的对比(8家SMS供应商对比)
- 百度竞价广告的URL设置
- 《2022爱分析·人工智能应用实践报告》发布:从点到面,人工智能推动企业智能化转型
- app调起支付宝-后端预支付
- XML Schema学习札记(1)——基础总览
- 电视软件测试项目怎么做,LED_TV液晶电视软件测试用例.doc
- Visual Studio 2017 下载地址 V15各种版本官方下载网址
- TMT: A Transformer-based Modal Translator for Improving Multimodal Sequence Representations in Audio
- ssm 一对多的映射关系
- Java中高级面试题部分答案解析(3)
- 关于Java中的除以零的研究
- java 读取excel数据格式转换