【python原理解析】gc原理初步解析
python的gc是会用到:引用计数、标记-清除和分代收集,首先说明一下什么是引用计数
可以通过sys模块中的getrefcount()方法获取某个对象的引用计数
python本身的数据类型有基础类型和容器类型,基础类型包含:整型、布尔型、浮点型、字符串型,容器类型就是说可以将其他对象包含在其中的类型,如:list、set、dict等都是容器类型
以基础类型的整型为例:
def f11():
a = 1
b = 1
print sys.getrefcount(a)
print sys.getrefcount(b)
b = a
print sys.getrefcount(a)
print sys.getrefcount(b)
运行结果:(在当时的情况下)
150
150
150
150
增加引用计数的方式是:
(1)使用=等号赋值
(2)在容器对象中使用对象
(3)作为函数参数传递的时候
我们可以通过下面的函数看到:
def f1():
gc.set_debug(gc.DEBUG_STATS|gc.DEBUG_LEAK)
a=[]
b=[]
a.append(b)
print 'a refcount:',sys.getrefcount(a) # 2
print 'b refcount:',sys.getrefcount(b) # 3
del a
del b
print gc.collect() # 0
结果为:

那么可以看到:a和b在被赋值之后,refcount的值都变成了1,a引用了b之后,b的refcount值增加1变成了2;那么,为什么打印出来的结果分别是2和3呢?因为sys.getrefcount()的函数的时候,将a作为参数了,此时a的引用计数就会增加1,所以通过该方法打印出来的结果就是会比预期的结果多1
那么引用计数增加之后,如何减少引用计数呢?一般的方法有:
(1)使用del语句,可以减少一个计数
(2)改变引用,给变量名设置别的对象
(3)离开作用域
那么上面的def f1()中,其实可以看到:del a和b之后,可以看到这个a和b是处于0代链表的,直接清理即可;del的作用是:它不仅会移除一个对象的引用,还会移除那个名字本身。
接下来说明一下:循环引用的问题
循环引用出现在:容器类对象相互包含的情况下,
def f2():
a=[]
b=[]
a.append(b)
b.append(a)
print 'a refcount:',sys.getrefcount(a) # 3
print 'b refcount:',sys.getrefcount(b) # 3
print gc.collect()
del a
del b
print gc.collect()
例如def f2()中的结果如下:

可以看到gc.collect()在del之前和之后的结果不同,看了一下gc.collect()的含义以及返回值,(重点是:返回值是unreachable objects的数量被返回)

因此分析一下def f2()中的程序可以看出,在没有调用删除a之前,程序中没有不可达对象,删除a之后,因为a和b的循环引用,导致都变成不可达对象
那么什么是不可达对象?与之对象,可达对象是什么?是在什么情况下产生的?例如A引用B,则从A到B就会建立一个连接,从A指向B,从根节点开始(根节点一般是全局变量等)一直往下扫描,比如A引用B,B引用C,D引用C,那么A是root,则A-B-C都是可达的,但是D不是可达的,因此D就是unreachable的对象,可以释放的
我们可以看到在refcount之后,循环引用的,最终的引用计数无法=0,基于引用计数=0的清除机制无法执行,则需要通过“标记-清除”的方式来进一步将引用计数进行确定处理,“标记-清除”的执行逻辑是:
(1)对于每一个容器对象,都设置了gc_refs值,并将其设置为该对象的引用计数值
(2)对于每一个容器对象,找到所有其引用的对象,将被引用的对象的gc_refs值减1
(3)执行完(2)的所有容器对象,所有的gc_refs还大于0的对象都代表着被非容器对象引用,说明至少包含一个非循环引用,因此这些对象不能释放,就需要将其加入到另一个集合中
(4)在(3)中不能释放的对象,如果他们引用某个对象,则这些对象也不能释放,将这些对象也加入到另一个集合中
(5)经过上面步骤后,最终得到的就是不可达的对象,这些对象就是需要释放的对象
那么如何释放呢?以及释放的频率以及触发时机如何控制呢?
就要用到分代收集,在python中,会将对象分别加入到不同的收集链表中,依据规则:活的越久的对象越不是垃圾,回收的频率越低;分成了0代,1代和2代,其中越年轻的越会被清理,并且清理1代的时候0代也会清理,清理2代的时候1代和0代也会被清理
这个可以通过调用函数:gc.get_threshold()来实现
print gc.get_threshold()
打印结果如下:(700, 10, 10)
这个函数的返回值有三个,第一个返回值代表的是:从上一次收集开始,所有新增的对象减去删除的对象大于threshold0的时候就开始一次新的收集;第二个返回值代表的是:如果0代的对象被检查的次数超过了threshold1,则1代的检查就要执行;第三个返回值代表的是:1代的对象被检查超过了threshold2,则2代的检查就应该被执行
这三个值的具体含义可以通过gc.set_threshold()方法来查看:

【python原理解析】gc原理初步解析的更多相关文章
- Thrift之代码生成器Compiler原理及源码详细解析1
我的新浪微博:http://weibo.com/freshairbrucewoo. 欢迎大家相互交流,共同提高技术. 又很久没有写博客了,最近忙着研究GlusterFS,本来周末打算写几篇博客的,但是 ...
- 并发编程(十五)——定时器 ScheduledThreadPoolExecutor 实现原理与源码深度解析
在上一篇线程池的文章<并发编程(十一)—— Java 线程池 实现原理与源码深度解析(一)>中从ThreadPoolExecutor源码分析了其运行机制.限于篇幅,留下了Scheduled ...
- 并发编程(十二)—— Java 线程池 实现原理与源码深度解析 之 submit 方法 (二)
在上一篇<并发编程(十一)—— Java 线程池 实现原理与源码深度解析(一)>中提到了线程池ThreadPoolExecutor的原理以及它的execute方法.这篇文章是接着上一篇文章 ...
- 浏览器解析JavaScript原理
1.浏览器解析JavaScript原理特点: 1.跨平台 2.弱类型 javascript 定义的时候不需要定义数据类型,数据类型是根据变量值来确定的. var a = 10; 数字类型 ...
- LNP环境下Nginx与PHP配合解析的原理
正在理解中,查阅资料,加上自我理解,得出如下结论,如有错误,欢迎指正.... LNP环境,Nginx与PHP配合运行的原理解释: 以前的互联网时代我们成为web1.0时代,那时用户是被动接受网络信息, ...
- Digester解析xml原理
Tomcat内部是使用Digester来解析xml文件的,将xml转化为java对象. digester底层是基于SAX+事件驱动+栈的方式来搭建实现的,SAX主要用来解析xml,事件驱动主要是在解析 ...
- javascript解析器原理
浏览器在读取HTML文件的时候,只有当遇到<script>标签的时候,才会唤醒所谓的“JavaScript解析器”开始工作. JavaScript解析器工作步骤 1. “找一些东西”: v ...
- sqlalchemy mark-deleted 和 python 多继承下的方法解析顺序 MRO
sqlalchemy mark-deleted 和 python 多继承下的方法解析顺序 MRO 今天在弄一个 sqlalchemy 的数据库基类的时候,遇到了跟多继承相关的一个小问题,因此顺便看了一 ...
- 【转】Java 内存模型及GC原理
一个优秀Java程序员,必须了解Java内存模型.GC工作原理,以及如何优化GC的性能.与GC进行有限的交互,有一些应用程序对性能要求较高,例如嵌入式系统.实时系统等,只有全面提升内存的管理效率,才能 ...
- Python程序的执行原理(转载)
Python程序的执行原理 2013-09-17 10:35 佚名 tech.uc 1. 过程概述 Python先把代码(.py文件)编译成字节码,交给字节码虚拟机,然后虚拟机一条一条执行字节码指令 ...
随机推荐
- python:基本统计值计算(平均数,方差,中位数)
#CalStatisticsV1.py def getNum(): #获取用户不定长度的输入 nums=[] test=input("请输入要存储的数据(回车退出):") whil ...
- java Scanner中next和nextLine()区别
next(): 1.一定要读取到有效字符后才可以结束输入. 2.对输入有效字符之前遇到的空白,next() 方法会自动将其去掉. 3.只有输入有效字符后才将其后面输入的空白作为分隔符或者结束符. ne ...
- 如何用node命令和webpack命令传递参数 转载
1. 比如在项目中我们的publicPath需要根据服务器环境的变化而变化,这时我们会写一个配置文件,在webpack.config.js中读取,可以 如何才能 取到变量呢? 这里介绍一种方法: 如果 ...
- Spring Cloud(Dalston.SR5)--Zuul 网关-Hystrix 回退
当我们对网关进行配置让其调用集群的服务时,将会执行 Ribbon 路由过滤器,该过滤器在进行转发时会封装为一个 Hystrix 命令予以执行,Hystrix 命令具有容错的功能,如果"源服务 ...
- gdb调试嵌入式环境搭建
1.下载gdb源代码 http://ftp.gnu.org/gnu/gdb/ 2.编译 解压#tar zxvf gdb-7.9.1.tar.gz,cd到解压的目录中. 2.1编译arm-linux-g ...
- ActiveMQ-5.15.2下载和启动(windows)
一.下载和部署 我的ActiveMQ版本是 5.15.2,参照别人家的博客,下载和启动照样成功.别人家的博客地址: http://blog.csdn.net/clj198606061111/artic ...
- npm安装与使用
NPM 使用介绍 摘自:http://www.runoob.com/nodejs/nodejs-npm.html NPM是随同NodeJS一起安装的包管理工具,能解决NodeJS代码部署上的很多问题, ...
- 实验三:xen环境下的第一个虚拟机的安装
实验名称: xen环境下的第一个虚拟机的安装 实验环境: 我们这里继续上面实验二来完成这个实验: 环境则是xen的安装环境,如下图: 开启虚拟机的的硬件辅助虚拟化功能: 实验要求: 这里我们通过安装b ...
- JVM内容梳理
- gentoo Cataclysm - Dark Days Ahead
gentoo 中安装 Cataclysm - Dark Days Ahead,使用web 下载稳定版的安装包,使用 tar 进行解压. 安装需要共享库:sdl2-mixer, 未完待续