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. 3_多维数组转一维数组 reduce()

    一,二维数组转一维数组 1 //1. 二维数组转一维数组 2 let arr = [[0,1],[2,3],[4,5]] 3 let newArr = arr.reduce((pre,cur) =&g ...

  2. flask_apscheduler

    网上很多文章包括官网给出来的,更多的是执行的函数和初始话app在同一文件 按照app 路由 模型类 视图 往下延申,项目已经成型,所以上述的方法不适用. (不用操心模型类与app互相导入的错误)下面分 ...

  3. 增强MybatisPlus拓展新功能 实战MybatisPlus大合集

    mybatis-plus-max简介 MybatisPlusMax是MybatisPlus的增强包,秉承只拓展不修改的理念,对MybatisPlus做增强. 正如MybatisPlus是对MyBati ...

  4. 刷题笔记——3003.鸡兔同笼问题 & 2767.计算多项式的值

    题目1 3003.鸡兔同笼问题 代码 while True: try: x,y=map(int,input().strip().split()) a = int((4*x-y) / 2) b = x ...

  5. Hugging News #0106

    每一周,我们的同事都会向社区的成员们发布一些关于 Hugging Face 相关的更新,包括我们的产品和平台更新.社区活动.学习资源和内容更新.开源库和模型更新等,我们将其称之为「Hugging Ne ...

  6. git操作失误,提交代码因为网络问题没有成功,然后操作时候点错按钮导致代码全部没有了,也没用备份,如何解决

    最好的提交代码办法, 1.先创建一个空文件夹, 2.然后创建一个在线仓库 3. git remote add origin '仓库地址' 4.查看远程仓库 git remote remove orig ...

  7. 顶层QWidget弹窗设置背景为透明,透明部分为黑色。

    setAttribute(Qt::WA_TranslucentBackground); 设置此属性,解决.

  8. ADC-单通道DMA到多通道DMA ADC采集修改事项

    1. 使能通道IO,因为从单通道到多通道,需要添加规则转换通道数,故需要使能扫描模式,否则只能扫描第一个通道: 2. DMA模式配置需修改为循环传输模式,否则只转换一次: 3. 开启ADC规则转换通道 ...

  9. ADC-CH32FV2x_V3x 框图功能详解

    主要特性(CH32FV2x_V3x) 系列:l 12 位分辨率l 支持 16 个外部通道和 2 个内部信号源采样l 多通道的多种采样转换方式:单次.连续.扫描.触发.间断等l 数据对齐模式:左对齐.右 ...

  10. 微信小程序搜索优化指南(SEO)

    前言 其实在 2019 年上半年,微信就发布了基于小程序页面的搜索. 为了更好地发现及理解小程序的页面,结合过去一段时间来我们遇到的各种情况,强烈建议各位开发者花一些宝贵的时间认真阅读本文. 小程序爬 ...