Python 中的垃圾回收机制总结(1)

news2024/11/23 18:41:44

1.背景

对于Python来说,一切皆为对象,所有的变量赋值都遵循着对象引用机制。

程序在电脑上运行的时候,需要在内存中开辟出一块空间,用于存放运行时产生的临时变量,一方面,内存的容量是有限的;另一方面内存空间的申请与回收是非常耗费精力的事情,而且存在很大的危险性,稍有不慎就有可能引发内存溢出问题,好在Cpython解释器提供了自动的垃圾回收机制来帮我们解决了这件事。

内存溢出:数据量过大时内存空间管理不善就很容易出现 OOM(out of memory),俗称爆内存或者内存溢出,导致程序可能被操作系统中止。

内存泄漏:不是指你的内存在物理上消失了,也不是说你的内存被恶意程序利用出现了信息安全问题,而是指程序本身没有设计好,未能及时释放已不再使用的内存,导致失去了对这段内存的控制,从而造成了内存的浪费(或者说这块内存脱离了垃圾回收机制的控制)

1.1 什么是垃圾回收机制?

垃圾回收机制(简称GC)是 Python 解释器自带一种机,专门用来回收不可用的变量值所占用的内存空间

1.2 为什么要有垃圾回收机制?

程序运行过程中会申请大量的内存空间,而对于一些无用的内存空间如果不及时清理的话会导致内存使用殆尽(内存溢出),导致程序崩溃,因此管理内存是一件重要且繁杂的事情,而python解释器自带的垃圾回收机制把程序员从繁杂的内存管理中解放出来

1.3 什么时候进行垃圾回收?

由于变量名是访问到变量值的唯一方式,所以当一个变量值不再关联任何变量名时,我们就无法再访问到该变量值了,该变量值就是没有用的,就应该被当成一个垃圾回收。

1.4 垃圾回收机制原理分析

Python 的 GC 模块主要运用了引用计数”(reference counting) 来跟踪和回收垃圾。在引用计数的基础上,还可以通过“标记-清除”(mark and sweep)解决容器对象可能产生的循环引用的问题,并且通过“分代回收”(generation collection)以空间换取时间的方式来进一步提高垃圾回收的效率。

用一句话来形容就是:引用计数机制为主,标记-清除和分代收集两种机制为辅的策略

1.5 垃圾回收机制的分类

  • 引用计数
  • 标记清楚
  • 分代回收

2.引用计数机制

2.1 引用计数法机制的原理

每个对象维护一个 ob_ref 字段,用来记录该对象当前被引用的次数,每当新的引用指向该对象时,它的引用计数 ob_ref 加 1,每当该对象的引用失效时计数 ob_ref 减 1,一旦对象的引用计数为 0,该对象立即被回收,对象占用的内存空间将被释放。

缺点

  • 需要额外的空间维护引用计数
  • 不能解决对象的循环引用

优点

  • 高效,运行期没有停顿 可以类比一下Ruby的垃圾回收机制,也就是
  • 实时性:一旦没有引用,内存就直接释放。不用像其他机制等到特定时机。
  • 处理回收内存的时间分摊到了平时
  • 对象有确定的生命周期,而且易于实现

导致引用计数+1的情况

  • 对象被创建,例如a=23
  • 对象被引用,例如b=a
  • 对象被作为参数,传入到一个函数中,例如func(a)
  • 对象作为一个元素,存储在容器中,例如list1=[a,a]

导致引用计数-1的情况

  • 对象的别名被显式销毁,例如del a
  • 对象的别名被赋予新的对象,例如a=24
  • 一个对象离开它的作用域,例如:func函数执行完毕时,func函数中的局部变量(全局变量不会)
  • 对象所在的容器被销毁,或从容器中删除对象

2.2 循环引用导致内存泄露

def f2():
    '''循环引用'''
    while True:
        c1=A()
        c2=A()
        print("c1引用次数:%s, c2引用次数:%s"%(sys.getrefcount(c1) - 1,sys.getrefcount(c2) - 1))
        c1.t=c2
        print("c1引用次数:%s, c2引用次数:%s"%(sys.getrefcount(c1) - 1,sys.getrefcount(c2) - 1))
        c2.t=c1
        print("c1引用次数:%s, c2引用次数:%s"%(sys.getrefcount(c1) - 1,sys.getrefcount(c2) - 1))
        del c1
        del c2
        break
        
f2()
object born id:0x1074a0b38
object born id:0x1074a0c50
c1引用次数:1, c2引用次数:1
c1引用次数:1, c2引用次数:2
c1引用次数:2, c2引用次数:2
  • 创建了c1,c2后,这两个对象的引用计数都是1,执行c1.t=c2和c2.t=c1后,引用计数变成2.
  • 在del c1后,内存c1的对象的引用计数变为1,由于不是为0,所以c1的对象不会被销毁,同理,在del c2后也是一样的。
  • 虽然它们两个的对象都是可以被销毁的,但是由于循环引用,导致垃圾回收器都不会回收它们,所以就会导致内存泄露。
  • 引用计数查看的代码:
import sys
sys.getrefcount(obj) - 1

3.标记清除

标记清除(Mark—Sweep)主要是回收循环引用的对象,显然,像是PyIntObject、PyStringObject这些不可变对象是不可能产生循环引用的,因为它们内部不可能持有其它对象的引用。Python中的循环引用总是发生在 container 对象之间,也就是能够在内部持有其它对象的对象,比如list、dict、class等等。这也使得该方法带来的开销只依赖于container对象的的数量。

原理解释:

首先标记对象(垃圾检测),然后清除垃圾(垃圾回收),首先初始所有对象标记为白色,并确定根节点对象(这些对象是不会被删除),标记它们为黑色(表示对象有效),将有效对象引用的对象标记为灰色(表示对象可达,但它们所引用的对象还没检查),检查完灰色对象引用的对象后,将灰色标记为黑色。重复直到不存在灰色节点为止。最后白色结点都是需要清除的对象。
在这里插入图片描述

标记清除底层机制:

  • 收集所有的容器对象, 通过一个双向链表进行引用 (容器对象:列表、元祖、字典 )
  • 针对于每一个容器对象,通过一个变量gc_refs 来记录当前对应的引用计数
  • 找到每个容器对象,找到它引用的容器对象,并将这个容器的引用计数-1
  • 经过步骤3之后, 如果一个容器对象的引用计数为0, 就代表该对象可以被回收了, 循环引用导致其活到现在的

缺点:该机制所带来的额外操作和需要回收的内存块成正比

4.分代回收

分代回收是一种以空间换时间的操作方式,Python将内存根据对象的存活时间划分为不同的集合,每个集合称为一个代,Python将内存分为了3“代”,分别为年轻代(第0代)、中年代(第1代)、老年代(第2代),他们对应的是3个链表,它们的垃圾收集频率随着对象存活时间的增大而减小

新创建的对象都会分配在年轻代,年轻代链表的总数达到上限时,Python垃圾收集机制就会被触发,把那些可以被回收的对象回收掉,而那些不会回收的对象就会被移到中年代去,依此类推,老年代中的对象是存活时间最久的对象,甚至是存活于整个系统的生命周期内。
同时,分代回收是建立在标记清除技术基础之上。
在这里插入图片描述
分代回收同样作为Python的辅助垃圾收集技术处理那些容器对象。

参考文档

  • https://blog.51cto.com/u_15222272/5576251
  • https://blog.csdn.net/a6864657/article/details/128202002
  • http://testingpai.com/article/1630130800949

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/89873.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JNPF3.4.5消息模块:多渠道应用,配置灵活多样,满足更多使用场景

自11月15日,JNPF 3.4.5 JAVA版本上线,就受到了众多用户的广泛好评,此次更新为用户带来了不同以往的使用体验。 在本次更新中,所有工作流都可以实现自主配置消息模板的操作,同时包括站内信,也可以实现自主配…

sublime json美化

sublime 的插件 json美化感觉很难用,好多正常的json串都 不能正常解析 ,自己写了一个json解析插件,此插件跟网上教程的json美化插件 不同的是: 只对json的特殊字符进行格式化 { [ ] } : , 这种不是很严格但是正好解决了我的问…

【Redis】Redis 持久化

文章目录概述RDB触发机制如何恢复 rdb 文件?RDB 优点:RDB 缺点:AOFAOF 优点AOF 缺点概述 Redis 是内存数据库,如果不将内存中的数据库状态保存到磁盘,那么服务器一旦进程退出,服务器中的数据库状态也会消失…

【C语言进阶】一文速通面试中的指针相关疑难杂症(内含模拟库函数 qsort 的实现)

目录 🥇前言🥇: 一、指向函数指针数组的指针🤯: 1.书写格式🦚: 2.指向函数指针数组指针示例🦩: 二、回调函数🧐: 1.回调函数的定义&#x1f99…

嵌入式软件工程师技能树——应用编程/网络编程/驱动开发/操作系统/计算机网络

文章目录Linux驱动开发1、Linux内核组成2、用户空间与内核的通讯方式有哪些?3、系统调用read/write流程4、内核态用户态的区别5、bootloader内核 根文件的关系6、BootLoader的作用7、BootLoader两个启动阶段1、汇编实现,完成依赖于CPU体系架构的设置&…

Win10安装Linux虚拟机-安装与使用

Win10安装Linux虚拟机-安装与使用 1、VMware 的下载 VMWare虚拟机软件是一个“虚拟PC”软件,它使你可以在一台机器上同时运行二个或更多Windows、DOS、LINUX系统。 下载地址:https://customerconnect.vmware.com/en/downloads/#all_products 在搜索中…

用 Charles 断点调试 HTTPS 请求,原理解析

现在的网站基本都是 https 的,而 charles 是常用的 http 抓包工具,所以用 charles 调试 https 请求是常见的需求。 今天就分享下如何用 charles 调试 https 请求,如何打断点。 首先安装 charles,点击 start recording&#xff1…

FineReport平台数据分析-图表显示部分系列接口

1. 概述 1.1 应用场景 当图表系列较多时,用户希望可以自己设置哪些系列显示,哪些系列不显示。以决策报表为例,实现效果如下图: 1.2 实现思路 通过FR.Chart.WebUtils.getChart("chartID").getChartWithIndex(chartInde…

静态HTML旅行主题网页作业——青岛民俗7页html+css+javascript+jquery 地方民俗网页设计与实现

👨‍🎓静态网站的编写主要是用 HTML DⅣV CSSJS等来完成页面的排版设计👩‍🎓,一般的网页作业需要融入以下知识点:div布局、浮动定位、高级css、表格、表单及验证、js轮播图、音频视频Fash的应用、uli、下拉…

web开发:linux常用命令总结

1.关于目录操作: (1)ls 列出当前目录下都有哪些文件/目录 也可以写成: ls 指定目录 列出指定目录下的文件/目录 还可以写成 ls -l 指定目录 以列表的形式列出 或缩写成 ll 指定目录 (2)pwd 查看当前…

shared_ptr

先看源码 template<typename _Tp> class shared_ptr : public __shared_ptr<_Tp> {template<typename... _Args>using _Constructible typename enable_if<is_constructible<__shared_ptr<_Tp>, _Args...>::value>::type;template<ty…

【TuyaOS开发之旅】环境搭建

前言 涂鸦最近更新了打磨良久的TuyaOS&#xff0c;整体使用感受非常的nice。所以决定写一个专栏讲解一下TuyaOS的入门使用&#xff0c;来方便小白快速的入门和熟悉TuyaOS的开发。 官方环境搭建教程 Tuya Wind IDE-TuyaOS-涂鸦开发者 报错和解决 暂无 补充 程序下载方法 …

MetaFormer实际上是你所需要的视觉

transformer在计算机视觉任务中显示出了巨大的潜力。人们普遍认为&#xff0c;他们基于注意力的token混合器模块对他们的能力贡献最大。然而&#xff0c;最近的工作表明&#xff0c;transformer中基于注意力的模块可以被空间mlp取代&#xff0c;得到的模型仍然表现相当好。基于…

11.关联容器

文章目录关联容器11.1使用关联容器使用map使用set11.2关联容器概述11.2.1定义关联容器初始化multimap或multiset11.2.2关键字类型的要求有序容器的关键字类型使用关键字类型的比较函数11.2.3pair类型创建pair对象的函数11.3关联容器操作11.3.1关联容器迭代器set的迭代器是const…

为什么Docker比VM虚拟机快?

(1)docker有着比虚拟机更少的抽象层 由于docker不需要Hypervisor(虚拟机)实现硬件资源虚拟化&#xff0c;运行在docker容器上的程序直接使用的都是实际物理机的硬件资源。因此在CPU、内存利用率上docker将会在效率上有明显优势。 (2)docker利用的是宿主机的内核,而不需要加载操…

基于springboot招生管理系统设计与实现的源码+文档

摘 要 在Internet高速发展的今天&#xff0c;我们生活的各个领域都涉及到计算机的应用&#xff0c;其中包括招生管理系统的网络应用&#xff0c;在外国招生管理系统已经是很普遍的方式&#xff0c;不过国内的管理网站可能还处于起步阶段。招生管理系统具有招生公告信息管理功能…

实训任务一

文章目录实训任务一一、实训任务1、创建并且配置三个虚拟机2、创建SSH连接3、实现IP地址与主机名的映射4、关闭和禁用防火墙5、创建目录结构6、压缩打包7、安装软件包8、创建脚本文件9、直接运行脚本10、虚拟机相互免密登录11、远程拷贝文件实训任务一 需求&#xff1a;熟练掌…

java+MySQL 基于ssm高校创新实践学分认定系统

随着现代实践学分认定的快速发展,可以说实践学分认定已经逐渐成为现代实践学分认定过程中最为重要的部分之一。但是一直以来我国传统的实践学分认定并没有建立一套完善的行之有效的实践学分认定系统,传统的实践学分认定已经无法适应高速发展,无论是从效率还是从效果来看都远远的…

问题解决之:chatGPT 登录页面的 google 验证 reCAPTCHA 弹不出来

文章目录问题描述自己的境况分析结论问题描述 今天我到了图书馆想访问一下 chatgpt&#xff0c;挂了 vpn 之后所有的浏览器都无法弹出 reCAPTCHA 人机验证&#xff0c;即使我更换了不同的 vpn 和为 chrome 的 reCAPTCHA 设置了重定向也无法成功 正常情况&#xff1a;应该弹…

基于B\S的《C语言程序设计》学习网站的设计与实现

开发工具(eclipse/idea/vscode等)&#xff1a; 数据库(sqlite/mysql/sqlserver等)&#xff1a; 功能模块(请用文字描述&#xff0c;至少200字)&#xff1a; 1)系统平面设计&#xff1a;设计精美、简洁且清爽的系统界面。 2)课程信息管理&#xff1a;对课程的基本信息、课程目标…