python垃圾回收机制

一、引入

解释器在执行定义变量的语法时,会申请内存空间来存放变量值,每一块内存空间都有其唯一的内存地址,我们在前面说过,变量名并不是存放的变量值,而是存放的内存地址,通过访问内存地址,就能找到对应的值,而内存的容量是有限的,因此必然会有一些内存空间被回收然后再提供给用户使用,这就是回收内存空间。

那么回收哪些值所在的内存空间呢?或者说,存放哪些值的内存就应该被回收呢?答案:没有用了的值就会变成垃圾就会被回收掉。那么问题又来了,哪些值是没有用的呢?怎么判断一个值是否有用,是否无用呢?

二、什么是垃圾?

前面我们说到,没有用的值就会变成垃圾,其所在的内存空间就会被回收掉。而我们定义变量去存储值的目的也是为了使用值,而访问变量值需要通过直接引用(比如x=10,直接使用x即可)或者间接引用(l = [x,20],10被x直接引用,从而通过列表l可以间接访问到10),所以当一个变量值不再绑定任何引用时,我们就无法再访问到该变量值了,该变量值就成了垃圾

三、垃圾回收机制

垃圾回收机制(简称GC)是python解释器自带的一种机制,专门用来回收没有绑定任何引用(直接引用和间接引用)的变量值所在的内存空间

四、理解GC需要的储备知识

1、堆区与栈区

在定义变量时,变量名与变量值都是需要存储的,分别对应内存中的两块区域:堆区与栈区

当我们执行x = y时,就会变成

此时x和y指向同一块内存空间,当我们修改y所绑定的值的时候,同时也会修改x

2、直接引用和间接引用

直接引用:从栈区出发直接通过内存地址找到堆区对应的值

间接引用:从栈区出发在堆区中找到内存地址,再用找到的内存地址再在堆区中寻找对应的值

通过下面的图来进一步理解

x = 10
y = 20
l = [x,y]

x,y和列表l在内存中的实际存储方式是下图中这样的

五、GC详解

python中的垃圾回收机制主要是应用了“引用计数”来跟踪和回收垃圾

1、引用计数

引用计数:变量值被变量名关联的次数

例如:age = 18,变量值18倍变量名age关联了,则18的引用计数为1

此时,再另age_of_cuihua = age,则age_of_cuihua和age都关联了18,此时18的引用计数增加为2,

如果另age = 80,此时age和80建立了起了联系,age和18就没有联系了,则18的引用计数减少为1,

我再del age_of_cuihua(del的意思就是解除变量名与变量值之间的绑定关系),此时18的引用计数为0。

当变量值的引用计数变成0时,就会触发垃圾回收机制,18所在的内存空间就会被回收掉

2、引用计数产生的问题

2.1、问题一:循环引用

l1 = ['pig'] # 此时,列表1被引用了一次,列表1的引用计数变成了1
l2 = ['dog'] # 此时,列表2被引用了一次,列表2的引用计数变成了1 # 要放大招了
l1.append(l2) # l1列表中添加l2,此时列表l2又被引用了一次,引用计数变成了2
l2.append(l1) # l2列表中添加l1,此时列表l1又被引用了一次,引用计数变成了2 # ??????这是什么操作,我们打印出来看一看 print(l1) # ['pig', ['dog', [...]]]
print(l2) # ['dog', ['pig', [...]]]

让我们此时画图来分析一下其中的原理

这就是循环引用,我中有你,你中有我

此时做一个大胆的操作

del l1
del l2

????这次又发生了什么,我们再画一个图看看

上面说过,del的作用是解除变量名与变量值之间的绑定关系,那么此时已经无法通过变量名l1和l2访问两个列表了,这两个列表的引用计数再次由2减少成了1。

但此时,我们惊人的发现,已经没有任何办法去访问两个列表了,那么这两个列表已经没用了,正式宣告成为了垃圾,是应该被回收的,但是这两个列表的引用计数还为1,是不能被回收的,这就和我们之前说过的根据引用计数回收垃圾相矛盾了,即按照引用计数回收垃圾,这个方法竟然失灵了。

也就是说,引用计数带来的影响很致命,如果我们大量使用引用计数,那么,我们的内存空间,会被一点一点的吞噬掉,该怎么解决这个问题呢?

2.2、解决方案:标记-清除

标记-清除原理:当应用程序可用的内存空间被耗尽时,就会停止整个程序,然后进行两项工作,标记和清除

标记:通俗的讲就是,栈区相当于“根”,凡是通过根出发可以直接访问或者间接访问到的都是“有根之人”,有跟之人当活,无根之人当死;具体的讲,标记的过程其实就是遍历所有的GC Roots对象(栈区中的所有内容或者线程都可以称之为GC Roots对象),然后将其中可以直接或者间接访问到的对象都标记为可以存活的对象,其余的为非存活对象,应该清除掉

清除:清除所有没有被标记的非存活对象

基于该算法,当我们解除掉变量名l1和l2与两个列表中的绑定关系的时候,两个列表会被标记为非存活对象,等待清除,无需我们手动去清除

2.3、问题二:效率问题

标记-清除需要遍历堆区中所有的对象,每次回收内存,都要遍历一遍,这个工作量是非常庞大的,因此即为耗时,于是引入了“分代回收”算法,分代回收采用了以空间换时间的策略

2.4、解决方案:分代回收

分代回收原理:分代指的是根据存活时间来划分不同等级(也就是不同的代),假如分成了幼儿代,青春代,中年代,老年代五个代,一个变量一开始假如在幼儿代,一段时间内被扫描了三次,依然有绑定关系,此时就把这个变量移入更加高级的青春代,扫描的时候会优先扫描幼儿代,然后再扫描更高级的代

虽然分代回收能起到提高效率的效果,但也存在着一定的问题,比如一个变量刚从幼儿代移入了青春代,但它的绑定关系被解除,此时不会及时的扫描到这个变量,释放内存

04-python垃圾回收机制的更多相关文章

  1. python垃圾回收机制与小整数池

    python垃圾回收机制 当引用计数为0时,python会删除这个值. 引用计数 x = 10 y = x del x print(y) 10 引用计数+1,引用计数+1,引用计数-1,此时引用计数为 ...

  2. python垃圾回收机制:引用计数 VS js垃圾回收机制:标记清除

    js垃圾回收机制:标记清除 Js具有自动垃圾回收机制.垃圾收集器会按照固定的时间间隔周期性的执行. JS中最常见的垃圾回收方式是标记清除. 工作原理 当变量进入环境时,将这个变量标记为"进入 ...

  3. 浅析Python垃圾回收机制!

    Python垃圾回收机制 目录 Python垃圾回收机制 1. 内存泄露 2. Python什么时候启动垃圾回收机制? 2.1 计数引用 2.2 循环引用 问题:引用计数是0是启动垃圾回收的充要条件吗 ...

  4. 简述Python垃圾回收机制和常量池的验证

    目录 通过代码验证python解释器内部使用了常量池 Python的引入 变量的引入 为什么要有变量 定义变量 常量引入 常量池引入 Python解释器 Python变量存储机制 Python垃圾回收 ...

  5. 从 CPython 源码角度看 Python 垃圾回收机制

    环状双向链表 refchain 在 Python 程序中创建的任何对象都会被放到 refchain 链表中,当创建一个 Python 对象时,内部实际上创建了一些基本的数据: 上一个对象 下一个对象 ...

  6. python垃圾回收机制的一些理解

    概览:       主要通过 引用计数来进行垃圾收集, 就是说,当一个对象没有被其他对象引用的时候,会释放掉内存.     但是会有一些循环引用的对象,通过上面的方法,是没有办法清除掉的.所以,pyt ...

  7. Python垃圾回收机制详解

    一.垃圾回收机制 Python中的垃圾回收是以引用计数为主,分代收集为辅.引用计数的缺陷是循环引用的问题. 在Python中,如果一个对象的引用数为0,Python虚拟机就会回收这个对象的内存. #e ...

  8. Python垃圾回收机制 总结

    Python 垃圾回收机制 内存管理 Python中的内存管理机制的层次结构提供了4层,其中最底层则是C运行的malloc和free接口,往上的三层才是由Python实现并且维护的,第一层则是在第0层 ...

  9. python 垃圾回收机制的思考

    一.前言 Python 是一门高级语言,使用起来类似于自然语言,开发的时候自然十分方便快捷,原因是Python在背后为我们默默做了很多事情,其中一件就是垃圾回收,来解决内存管理,内存泄漏的问题. 内存 ...

  10. Python垃圾回收机制--完美讲解!

    转自: http://www.jianshu.com/p/1e375fb40506 先来个概述,第二部分的画述才是厉害的. Garbage collection(GC) 现在的高级语言如java,c# ...

随机推荐

  1. 【转载】EXCEL VBA 工作表拆分

    用VBA拆分工作表是一个不错的方法,特别是在处理大量数据的时候,能节省不少时间.   1.高级筛选: 筛选并复制到新工作表的关键代码如下: Range("Database").Ad ...

  2. C/C++语言 MD5例子

    之前研究了一下在C中进行MD5加密,由于找了很久没有找到现成的库文件,所以所幸自己去写了一下.个人感觉C的便捷性没有Python好的原因就是这里. 下面是我写的一个例子. mian.cpp: 点击查看 ...

  3. 05.深入理解JMM和Happens-Before

    大家好,我是王有志. JMM都问啥? 最近沉迷P5R,所以写作的进度很不理想,但不得不说高卷杏YYDS.话不多说,开始今天的主题,JMM和Happens-Before. 关于它们的问题并不多,基本上只 ...

  4. Spark详解(01) - Scala编程语言

    Spark详解(01) - Scala编程语言概述 Scala官网:https://www.scala-lang.org/ 什么是Scala 从英文的角度来讲,Scala并不是一个单词,而是Scala ...

  5. 饮料换购【第六届蓝桥杯省赛C++A/C组,第六届蓝桥杯省赛JAVAB组】

    饮料换购 乐羊羊饮料厂正在举办一次促销优惠活动.乐羊羊C型饮料,凭3个瓶盖可以再换一瓶C型饮料,并且可以一直循环下去(但不允许暂借或赊账). 请你计算一下,如果小明不浪费瓶盖,尽量地参加活动,那么,对 ...

  6. 如何让Java编译器帮你写代码

    作者:京东零售 刘世杰 导读 本文结合京东监控埋点场景,对解决样板代码的技术选型方案进行分析,给出最终解决方案后,结合理论和实践进一步展开.通过关注文中的技术分析过程和技术场景,读者可收获一种样板代码 ...

  7. Scanner概述-Scanner使用步骤

    Scanner概述 了解了API的使用方式,我们通过Scanner类,熟悉一下查询API,并使用类的步骤. 什么是Scanner类 一个可以解析基本类型和字符串的简单文本扫描器. 例如,以下代码使用户 ...

  8. 如何找到CSDN中关注的用户和粉丝?

    如何找到CSDN中关注的用户和粉丝? 刚刚在CSDN个人账号里找了半天都没找到自己关注的人 对CSDN的页面更新感到很迷, 个人账号管理很不人性化, 或者说是根本找不到自己关注的用户以及关注自己的粉丝 ...

  9. 双缓冲技术解决MFC绘制闪烁问题

    闪烁的根源:OnEraseBkgnd一擦一写造成了图象颜色的反差导致闪烁 如何避免:首先要做的是屏蔽背景刷新.背景刷新其实是在响应WM_ERASEBKGND消息.我们在视类中添加对这个消息的响应 BO ...

  10. 找了几个 Solon 的商业落地项目案例!

    Solon 是啥?是一个高效的 Java 应用开发框架:更快.更小.更简单.(代码仓库:https://gitee.com/noear/solon) 提倡: 克制.简洁.开放.生态 启动快 5 - 1 ...