Python垃圾回收详解:引用计数+标记清理+分代回收
Python采用的是引用计数机制为主,标记-清理和分代收集两种机制为辅的策略。
1、引用计数
python中一切皆对象,所以python底层计数结构地就可以抽象为:
引用计数结构体{
引用计数;
引用的对象
}
是不是简单明了。现在我们先去考虑一下,什么情况下引用计数+1,什么情况下-1,当引用次数为0时,肯定就是需要进行回收的时刻。
引用计数+1的情况
1、对象被创建时,例如 mark="帅哥"
2、对象被copy引用时,例如 mark2=mark,此时mark引用计数+1
3、对象被作为参数,传入到一个函数中时
4、对象作为一个子元素,存储到容器中时,例如 list=[mark,mark2]
引用计数-1的情况
1、对象别名被显式销毁,例如 del mark
2、对象引用被赋予新的对象,例如mark2=mark3,此时mark引用计数-1(对照引用计数+1的情况下的第二点来看)
3、一个函数离开他的作用域,例如函数执行完成,它的引用参数的引用计数-1
4、对象所在容器被销毁,或者从容器中删除。
查看引用计数
实例:
import sys
a = "mark 帅哥"
print(sys.getrefcount(a))
引用计数机制优点
1、简单、直观
2、实时性,只要没有了引用就释放资源。
引用计数机制缺点
1、维护引用计数需要消耗一定的资源
2、循环应用时,无法回收。也正是因为这个原因,才需要通过标记-清理和分代收集机制来辅助引用计数机制。
2、标记-清理
由上面内容我们可以知道,引用计数机制有两个缺点,缺点1还可以勉强让人接受,缺点2如果不解决,肯定会引起内存泄露,为了解决这个问题,引入了标记删除。
我们先来看个实例,从实例中领会标记删除:
a=[1,2]#假设此时a的引用为1
b=[3,4]#假设此时b的引用为1
#循环引用
a.append(b)#b的引用+1=2
b.append(a)//a的引用+1=2
假如现在需要删除a,应该如何回收呢?(注意删除a可以使用del a,这样a这个引用就不存在了,但是它指向的对象,在标记删除后还存在,因为还被b使用者)
c=[5,6]#假设此时c的引用为1
d=[7,8]#假设此时d的引用为1
#循环引用
c.append(d)#c的引用+1=2
d.append(c)#d的引用+1=2
假如现在需要同时删除c、d,应该如何回收呢?
首先我们应该已经知道,不管上面两种情况的哪一个都无法只通过计数来完成回收,因为随便删除一个变量,它的引用只会-1,变成1,还是大于0,不会回收,为了解决这个问题,开始看标记删除来大展神威吧。
puthon标记删除时通过l两个容器来完成的:死亡容器、存活容器。
首先,我们先来分析情况2,删除c、d
删除后,c的引用为1,d的引用为1,根据引用计数,还无法删除
标记删除第一步:对执行删除操作后的每个引用-1,此时c的引用为0,d的引用为0,把他们都放到死亡容器内。把那些引用仍然大于0的放到存活容器内。
标记删除第二步:遍历存活容器,查看是否有的存活容器引用了死亡容器内的对象,如果有就把该对象(注意是对象,比如0x7f94bb602f80,不是对象的引用)从死亡容器内取出,放到存活容器内。
由于c、d都没有对象引用他们了,所以经过这一步骤,他们还是在死亡组。
标记删除第三部:将死亡组所有对象删除。
这样就完成了对从c、d的删除。
同样道理,我们来分析:只删除a的过程:
标记删除第一步:对执行删除(-1)后的每个引用-1,那么a的引用就是0,b的引用为1,将a放到死亡容器,将b放到存活容器。
标记删除第二步:循环存活容器,发现b引用a,复活a:将a放到存活容器内。
标记删除第三步:删除死亡容器内的所有对象。
综上所说,发现对于循环引用,必须将循环引用的双发对象都删除,才可以被回收。
标记-清理就是这么简单,
Python垃圾回收详解:引用计数+标记清理+分代回收的更多相关文章
- Python的垃圾回收机制(引用计数+标记清除+分代回收)
一.写在前面: 我们都知道Python一种面向对象的脚本语言,对象是Python中非常重要的一个概念.在Python中数字是对象,字符串是对象,任何事物都是对象,而它们的核心就是一个结构体--PyOb ...
- python9--内存管理 引用计数 标记清除 分代回收
复习 文件处理 1.操作文件的三步骤 -- 打开文件:硬盘的空间被操作系统持有 | 文件对象被应用程序持续 -- 操作文件:读写操作 -- 释放文件:释放操作系统对硬盘空间的持有 2.基础的读写 ...
- JVM中垃圾回收机制如何判断是否死亡?详解引用计数法和可达性分析 !
因为热爱,所以坚持. 文章下方有本文参考电子书和视频的下载地址哦~ 这节我们主要讲垃圾收集的一些基本概念,先了解垃圾收集是什么.然后触发条件是什么.最后虚拟机如何判断对象是否死亡. 一.前言 我们 ...
- python 垃圾回收详解
原文:https://zhuanlan.zhihu.com/p/31150408 总纲 策略和垃圾回收系统工作内容 引用计数详解 标记-清除+分代收集 循环引用 编程应用-常见方法 ex 过程详解 使 ...
- 基于Python对象引用、可变性和垃圾回收详解
基于Python对象引用.可变性和垃圾回收详解 下面小编就为大家带来一篇基于Python对象引用.可变性和垃圾回收详解.小编觉得挺不错的,现在就分享给大家,也给大家做个参考. 变量不是盒子 在示例所示 ...
- Java虚拟机之垃圾回收详解一
Java虚拟机之垃圾回收详解一 Java技术和JVM(Java虚拟机) 一.Java技术概述: Java是一门编程语言,是一种计算平台,是SUN公司于1995年首次发布.它是Java程序的技术基础,这 ...
- 深入理解JVM虚拟机3:垃圾回收器详解
JVM GC基本原理与GC算法 Java的内存分配与回收全部由JVM垃圾回收进程自动完成.与C语言不同,Java开发者不需要自己编写代码实现垃圾回收.这是Java深受大家欢迎的众多特性之一,能够帮助程 ...
- python协程详解
目录 python协程详解 一.什么是协程 二.了解协程的过程 1.yield工作原理 2.预激协程的装饰器 3.终止协程和异常处理 4.让协程返回值 5.yield from的使用 6.yield ...
- day 21 垃圾回收机制、标记删除及分代回收
垃圾回收机制 # 不能被程序访问到的数据,就称之为垃圾 引用计数 # 引用计数是用来记录值的内存地址被记录的次数的# 每一次对值地址的引用都可以使该值的引用计数 +1# 每一次对值地址的释放都可以使 ...
随机推荐
- IdentityServer4中AccessToken和IdentityToken中包含的Claims构成
贴出主要代码(以下源码的位置位于:IdentityServer4.Services.DefaultClaimsService) /// <summary> /// Returns clai ...
- C++ 将 std::string 转换为 char*
参考: std::string to char* C++ 将 std::string 转换为 char* 目前没有直接进行转换的方法.必须通过string对象的c_str()方法,获取C-style的 ...
- Java中的CAS实现原理
一.什么是CAS? 在计算机科学中,比较和交换(Conmpare And Swap)是用于实现多线程同步的原子指令. 它将内存位置的内容与给定值进行比较,只有在相同的情况下,将该内存位置的内容修改为新 ...
- QThread使用——关于run和movetoThread的区别
QThread 使用探讨 2010-10-23 00:30 注意:本文停止更新,请优先考虑 Qt 线程基础(QThread.QtConcurrent等) dbzhang800 2011.06.18 Q ...
- ubuntu 18.04安装clojure工程的cli工具lein
官网的安装过程https://leiningen.org/#install 是文字描述,并不够lazy. 我仿照code,chrome nodejs的方式,给出下面的命令行安装过程 wget http ...
- ES6标准之箭头函数
语法 具有一个参数的简单函数 var single = a => a single('hello, world') // 'hello, world' 没有参数的需要用在箭头前加上小括号 var ...
- Session 和 Cookie的区别
2019-03-26 18:16:47 一.区别概论 Session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群.数据库.文件中:Cookie是客户端保存用户信息的一种机制 ...
- hdoj5769后缀自动机版本
网上的题解都是后缀数组,我来个后缀自动机题解. 建好后缀自动机后由于后缀自动机是单向的,那么dfs一遍记录各节点的size,要保证一个节点只经过一次才是O(n),否则是O(n^2).表示这个节点及后面 ...
- node多项目合一打包
因为公司的需要,需要将多个项目合并为一个项目,具体要求是:多个项目中的公用部分提取出来,单独维护,业务部分则分别在不同的目录中,而我们的项目配置文件则作为公用部分单独维护,在项目打包的时候遇到一个问题 ...
- Luffy之注册认证(容联云通讯短信验证)
用户的注册认证 前端显示注册页面并调整首页头部和登陆页面的注册按钮的链接. 注册页面Register,主要是通过登录页面进行改成而成. 先构造前端页面 <template> <div ...