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. 封装 avm 组件经验分享

    avm.js 是一个跨端开发框架,AVM(Application-View-Model)前端组件化开发模式基于标准Web Components组件化思想,提供包含虚拟DOM和Runtime的编程框架a ...

  2. [OpenCV实战]31 使用OpenCV将一个三角形仿射变换到另一个三角形

    目录 1 什么是仿射变换? 2 使用OpenCV进行三角形仿射变换 2.1 定义输入和输出 2.2 计算边界框 2.3 裁剪图像和更改坐标 2.4 计算仿射变换矩形 2.5 应用仿射变换到三角形 2. ...

  3. 模型驱动设计的构造块(下)——DDD

    3. 领域对象的生命周期 每个对象都有生命周期,如下图所示.对象自创建后,可能会经历各种不同的状态,直至最终消亡--要么存档,要么删除.当然很多对象是简单的临时对象,仅通过调用构造函数来创建,用来做一 ...

  4. [WPF]限制程序单例运行

    代码 System.Threading.Mutex mutex; protected override void OnStartup(StartupEventArgs e) { bool ret; m ...

  5. 旋转卡壳(求凸包直径)学习笔记 | 题解 P1452 [USACO03FALL]Beauty Contest G /【模板】旋转卡壳

    前言 旋转卡壳(Rotating Calipers)可以在凸包上维护许多有用的信息,最常见的就是凸包直径(平面最远点对). 注意:本文不介绍所谓的 "人类智慧" 乱搞做法. 算法流 ...

  6. element上传图片组件使用方法|图片回显|格式转换base64

    upload上传组件的使用方法 上传图片后自动上传(也可以手动上传),图片上传成功后由后端返回特定图片地址,在表单提交后将表单数据同图片地址一并返回即可完成图片上传功能. 组件HTML <!-- ...

  7. 特定领域知识图谱(Domain-specific KnowledgeGraph:DKG)融合方案:技术知识前置【一】-文本匹配算法、知识融合学术界方案、知识融合业界落地方案、算法测评KG生产质量保障

    特定领域知识图谱(Domain-specific KnowledgeGraph:DKG)融合方案:技术知识前置[一]-文本匹配算法.知识融合学术界方案.知识融合业界落地方案.算法测评KG生产质量保障 ...

  8. CF1779C Least Prefix Sum 题解

    CF链接:Least Prefix Sum Luogu链接:Least Prefix Sum $ {\scr \color {CornflowerBlue}{\text{Solution}}} $ 先 ...

  9. 在Spring Boot中整合Katharsis,来快速开发JSON API的Web应用

    1 简介 我们进行Web API开发的时候,经常会使用Json格式的消息体,而Json格式非常灵活,不同的人会有不同的设计风格和实现,而JSON API提供了一套标准.但它并不提供直接实现. Kath ...

  10. FreeBSD 安装 fcitx5的配置

    link: Chinese Pinyin Package for typing Chinese sudo pkg install -y zh-CJKUnifonts sudo pkg install ...