04-python垃圾回收机制
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垃圾回收机制的更多相关文章
- python垃圾回收机制与小整数池
python垃圾回收机制 当引用计数为0时,python会删除这个值. 引用计数 x = 10 y = x del x print(y) 10 引用计数+1,引用计数+1,引用计数-1,此时引用计数为 ...
- python垃圾回收机制:引用计数 VS js垃圾回收机制:标记清除
js垃圾回收机制:标记清除 Js具有自动垃圾回收机制.垃圾收集器会按照固定的时间间隔周期性的执行. JS中最常见的垃圾回收方式是标记清除. 工作原理 当变量进入环境时,将这个变量标记为"进入 ...
- 浅析Python垃圾回收机制!
Python垃圾回收机制 目录 Python垃圾回收机制 1. 内存泄露 2. Python什么时候启动垃圾回收机制? 2.1 计数引用 2.2 循环引用 问题:引用计数是0是启动垃圾回收的充要条件吗 ...
- 简述Python垃圾回收机制和常量池的验证
目录 通过代码验证python解释器内部使用了常量池 Python的引入 变量的引入 为什么要有变量 定义变量 常量引入 常量池引入 Python解释器 Python变量存储机制 Python垃圾回收 ...
- 从 CPython 源码角度看 Python 垃圾回收机制
环状双向链表 refchain 在 Python 程序中创建的任何对象都会被放到 refchain 链表中,当创建一个 Python 对象时,内部实际上创建了一些基本的数据: 上一个对象 下一个对象 ...
- python垃圾回收机制的一些理解
概览: 主要通过 引用计数来进行垃圾收集, 就是说,当一个对象没有被其他对象引用的时候,会释放掉内存. 但是会有一些循环引用的对象,通过上面的方法,是没有办法清除掉的.所以,pyt ...
- Python垃圾回收机制详解
一.垃圾回收机制 Python中的垃圾回收是以引用计数为主,分代收集为辅.引用计数的缺陷是循环引用的问题. 在Python中,如果一个对象的引用数为0,Python虚拟机就会回收这个对象的内存. #e ...
- Python垃圾回收机制 总结
Python 垃圾回收机制 内存管理 Python中的内存管理机制的层次结构提供了4层,其中最底层则是C运行的malloc和free接口,往上的三层才是由Python实现并且维护的,第一层则是在第0层 ...
- python 垃圾回收机制的思考
一.前言 Python 是一门高级语言,使用起来类似于自然语言,开发的时候自然十分方便快捷,原因是Python在背后为我们默默做了很多事情,其中一件就是垃圾回收,来解决内存管理,内存泄漏的问题. 内存 ...
- Python垃圾回收机制--完美讲解!
转自: http://www.jianshu.com/p/1e375fb40506 先来个概述,第二部分的画述才是厉害的. Garbage collection(GC) 现在的高级语言如java,c# ...
随机推荐
- 使用IDEA创建一个maven的web项目并部署到tomcat上
目录 1.创建一个maven项目 2.为项目添加配置文件 3.创建一些类和jsp页面 4.将项目部署到tomcat 1.创建一个maven项目 打开IDEA,File--New--Project 选择 ...
- [OpenCV实战]46 在OpenCV下应用图像强度变换实现图像对比度均衡
本文主要介绍基于图像强度变换算法来实现图像对比度均衡.通过图像对比度均衡能够抑制图像中的无效信息,使图像转换为更符合计算机或人处理分析的形式,以提高图像的视觉价值和使用价值.本文主要通过OpenCV ...
- 那些年我们用过的组件-结构化日志组件 Serilog
什么是结构化日志 我们记录日志惯常使用 log4j2.NLog 等日志组件,这些组件提供了输出到多种终端的能力,但是大部分时候我们选择将日志输出到操作系统的文件系统中,为什么呢?至少有一部分原因是记录 ...
- Redis缓存何以一枝独秀?(2) —— 聊聊Redis的数据过期、数据淘汰以及数据持久化的实现机制
大家好,又见面了. 本文是笔者作为掘金技术社区签约作者的身份输出的缓存专栏系列内容,将会通过系列专题,讲清楚缓存的方方面面.如果感兴趣,欢迎关注以获取后续更新. 上一篇文章中呢,我们简单的介绍了下Re ...
- 琐碎的想法(五)for 的前世今生
for 起因 记得大学上C语言的课,第一次遇到的问题就是循环结构里面的 for. 选择结构的 if 非常易懂,和日常生活的判断没有区别. 循环结构的 while 同样比较好理解. 本质上是一个判断 如 ...
- 《Effective C++》模版与泛型编程
Item41:了解隐式接口和编译期多态. 纵使你从未使用过templates,应该不陌生"运行期多态"和"编译期多态"之间的差异.因为它类似于"哪一个 ...
- 轻松解决 CSS 代码都在一行的问题
前言 最近在做博客园的界面美化,用的是博客园[guangzan]的开源项目,配置超级简单,只需要复制粘贴代码就好啦. 但在粘贴 CSS 代码时遇到一个问题,那就是所有代码都挤在了一行,没有一点排板的样 ...
- 解决使用linux部署nodejs服务测试代码返回中文是乱码
今天写了个简单的node.js文件 代码如下 var http = require('http'); http.createServer(function (request, response) { ...
- NG-ZORRO + Angular11使用Echarts实现柱折线图-折柱混合,并给图表添加点击打印图表数据!!!详细代码
先上效果图 HTML代码 <div echarts #myEchart [options]="option"></div> ts代码 import { Co ...
- 大公司为什么禁止SpringBoot项目使用Tomcat?
本文已经收录到Github仓库,该仓库包含计算机基础.Java基础.多线程.JVM.数据库.Redis.Spring.Mybatis.SpringMVC.SpringBoot.分布式.微服务.设计模式 ...