首页 > 其他分享 >聊聊垃圾回收机制

聊聊垃圾回收机制

时间:2023-05-15 11:04:54浏览次数:39  
标签:变量 引用 内存空间 回收 内存 聊聊 垃圾

引入

  当解释器再执行到定义变量的语法时,会申请内存空间来存放变量的值,但是内存的容量时有限的,当你不需要该变量值时它仍然会占用你的内存空间,这就设计到了‘垃圾’的回收问题,当一个变量值没有用后我们应该将其回收掉以释放内存。

  单从逻辑层面分析,我们定义变量的值存起来是为了方便以后的取用,而取得一个存储的变量值就需要与其绑定的名称来直接或间接调用该值,所以当一个值没有再绑定任何索引时,我们就无法访问到这个存储的变量值了,此时这个存储的变量值也就变成了‘垃圾’,此时我们就应该想办法回收它。

  首先需要说的是,内存空间的申请和回收都是很耗费精力的事情,而且存在很大的危险性,稍有不慎就可能导致内存溢出,好在Cpython解释器提供了自动的垃圾回收机制来解决这件事。

 

什么是垃圾回收机制?

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

 

为什么要使用垃圾回收机制?

  在程序运行过程中会申请大量的内存空间,而对于一些无用的内存空间如果不及时清理就会导致内存溢出,即内存消耗殆尽,导致程序的崩溃,而内存管理是一件重要且繁杂的事情,我们使用垃圾回收机制的目的就是为了把程序员从繁杂的内存管理中解放出来。

 

理解垃圾回收机制(GC)

  堆区与栈区

     堆区和栈区是计算机内存中的两种不同的分配方式

栈区

  栈区是由编译器自动分配的内存空间,用于存储函数的参数值,局部变量的值等。栈区是顺序存储数据结构,遵循先进后出(LIFO)原则。当一个函数调用结束后,它的栈帧就会被自动释放,栈顶指针回到它的上一个位置

堆区

  堆区也是系统提供的内存空间,用于存储程序运行时动态分配的内存空间。堆区没有固定的大小,并且空间的申请和释放都是通过程序员手动控制的。当我们使用C++中的new操作符来创建对象时,对象就会被分配在堆区。需要注意的是,当我们不再需要这个对象时,需要手动使用delete操作符来释放其所占用的内存空间,否则会造成内存泄漏

 

总体来说,栈区的内存是自动管理的,操作简单,速度快,但是空间有限;而堆区的内存是手动管理的,灵活性高,但是容易产生内存泄漏等问题。在内存分配时,需要根据实际需要进行权衡

 

  直接引用与间接引用

    直接引用指的是从栈区出发直接引用到的内存地址。

    间接引用指的是从栈区出发引用到堆区后,再通过进一步引用才能到达的内存地址。

    图解见下:

 

垃圾回收机制原理分析   Python的GC模块主要运用的‘引用计数(reference counting)’来跟踪和回收垃圾。在引用计数的基础上,还可以通过‘标记清除(mark and sweep)’解决容器对象可能产生的循环引用的问题,并且通过‘分代回收(generation coliection)’以空间换取时间的方式来进一步提高垃圾回收的效率。   引用计数   变量值被变量名关联的次数,当这个值变为0,存储该垃圾的内存地址就会被垃圾回收机制回收。   引用计数的缺陷一:循环引用(也称交叉引用)问题

    我们使两个数据相互引用,然后断开变量名与内存地址的关联

  如上图可见,此时两个内存地址的引用技术均不为0,但不再被其他对象所关联,无人引用我们应该回收内存地址,但是由于他们的相互引用,内存无法被释放,所以Python引入了‘标记清除’和‘分代回收’来解决其循环引用的问题,并提升其效率。

 

  解决循环引用问题:标记清除

  容器对象都可以包含对其他对象的引用,都可能导致循环引用,标记清除就是为了解决这一问题。标记清除算法的做法是当应用程序可用的内存空间被耗尽时停止整个程序,然后进行标记和清除两项工作

  #1、标记
    标记的过程就是,遍历所有的GC Roots对象(栈区中的所有内容或者线程都可以作为GC Roots对象),然后将所有GC Roots的对象可以直接或间接访问到的对象标记为存活的对象,其余的均为非存活对象,应该被清除。

  #2、清除
    清除的过程就是将遍历堆中所有的对象,将没有标记的对象全部清除掉。

     在启用标记清除算法时,由于l1和l2已经被del,这时两者的内存地址就会被清理掉。

 

  引用计数的缺陷二:效率问题

  基于引用计数的回收机制,每次回收内存都需要把所有对象的引用计数遍历一边,这是非常浪费时间的,于是就引入了分代回收(空间换时间)用以提高回收效率

 

  解决效率问题:分代回收

分代

  在多次扫描后都没有被回收的变量,gc就会认为这是常用变量并降低对其的扫描频率,也就是说哦分代是根据存活时间来为变量划分不同等级(也就是不同的代)

  新定义的变量,放到新生代这个等级中,假设每隔1分钟扫描新生代一次,如果发现变量依然被引用,那么该对象的权重(权重本质就是个整数)加一,当变量的权重大于某个设定得值(假设为3),会将它移动到更高一级的青春代,青春代的gc扫描的频率低于新生代(扫描时间间隔更长),假设5分钟扫描青春代一次,这样每次gc需要扫描的变量的总个数就变少了,节省了扫描的总时间,接下来,青春代中的对象,也会以同样的方式被移动到老年代中。也就是等级(代)越高,被垃圾回收机制扫描的频率越低。

回收:仍然是基于引用计数的回收方式

分代回收的缺陷:

  假如一个变量刚刚从新生代移入青春代,该变量的绑定关系就被断了,该变量按理来说应该被回收,但青春代的扫描频率低于新生代,这就到导致了应该被回收的垃圾没有得到及时地清理而继续占用内存空间。

  但是毫无疑问,如果没有分代回收而使用引用计数机制一直不停地对所有变量进行全体扫描,固然可以更及时地清理掉垃圾占用的内存,但这种一直对所有变量进行全体扫描的方式效率极低,所有我们只能牺牲部分的空间来提升效率,这是一种折中的方法,是效率和内存空间的中和。

 

  综上,垃圾回收机制是在清理垃圾&释放内存的大背景下,允许分代回收以极小部分垃圾不会被及时释放为代价,以此换取引用计数整体扫描频率的降低,从而提升其性能,这是一种以空间换时间的解决方案

标签:变量,引用,内存空间,回收,内存,聊聊,垃圾
From: https://www.cnblogs.com/Cai-jia-hui/p/17400797.html

相关文章

  • Matlab代码#优化调度#计及电转气协同的含碳捕集与垃圾焚烧虚拟电厂优化调度
    Matlab代码#优化调度#计及电转气协同的含碳捕集与垃圾焚烧虚拟电厂优化调度#电转气协同、碳捕集、虚拟电厂优化调度#matlab程序,计及电转气协同的含碳捕集与垃圾焚烧虚拟电厂优化调度,看下面的图片是运行结果,程序不负责讲解,采用yalmip+cplex求解器求解。碳捕集,电转气,P2G,优化调度ID:......
  • Python垃圾回收机制
    什么是垃圾回收机制:垃圾回收机制(简称GC)是Python解释器自带一种机制,专门用来回收不可用的变量值所占用的内存空间为什么要用垃圾回收机制:程序运行过程中会申请大量的内存空间,而对于一些无用的内存空间如果不及时清理的话会导致内存使用殆尽(内存溢出),导致程序崩溃,因此管理内存是一......
  • 如何优雅地删除 Linux 中的垃圾文件
    本文正在参与“性能优化实战记录”话题征文活动不知道大家是否也跟我一样,是一只要把的自己电脑文件安排的条理有序,把没用的文件会及时删掉的程序猿呢?如果是的话,那么我们可以愉快地探讨下文章的内容。如果不是的话,你也可以留下来凑凑热闹嘛(>-<)。下面要介绍的是今天的主角——tm......
  • 垃圾收集器
    新生代SerialParNewParallelScavengeG1Zgc老年代SerialOldCmsParallelOldG1ZgcSTW-stoptheword当执行垃圾回收的时候会停止所有的业务线程Serial是单线程垃圾回收,当中会采取STW机制,如果业务量巨大占用内存过多,则会等待很长时间。采用的复制算法。......
  • 污水处理或雨水回收泵站控制 1、采用昆仑通态7寸新版触摸屏
    污水处理或雨水回收泵站控制1、采用昆仑通态7寸新版触摸屏mcgspro;2、plc采用西门子S7-200224XP自带模拟量输入;3、三个水泵,低液位停泵,中液位轮换启一台泵,高液位启动两台泵,超高液位启三台泵;4、超高水位降到高停个泵,高水位降压中水位停个泵,中水位降到低全部停泵,每次启动轮换输出…5......
  • Java 垃圾回收
    回收区域:java堆对象划分:新生代内存(YoungGeneration)老生代(OldGeneration)永久代(PermanentGeneration)永久代和原空间的区别在于元空间在直接内存上。堆的结构如上图所示。Eden,s0,s1为新生代,Tenured为老年代,最底下是永久代。内存分配规则一般新对象会分配到......
  • 即使垃圾也得卖
      经过两轮的冲刺,我们的软件做得并不是算的上的无可挑剔,直白点说就是一团垃圾,很事实的说,团队中贡献最低的我,很明显面临着被淘汰的风险,但是,我也有着留下的理由,我们的软甲在垃圾,但是也得卖也,那么我在接下来的营销阶段就有我的价值,同时,我也会努力完善我们的软件,让它不那么“垃圾......
  • 关于垃圾回收
    前言垃圾回收(GarbageCollection,以下简称GC),就是释放不用的内存,目的是防止内存泄漏。C/C++等较底层的语言需要在分配内存后手动释放内存,而Java、JavaScript等语言则可以在运行时根据需要自动释放内存,这是因为在这些语言的运行环境(如:JVM、V8等)中有GC在悄悄做着一些“杂活”......
  • 聊聊那些年我们实现java AOP几种常见套路
    前言有一定开发经验的同学对AOP应该很了解吧,如果不了解,可以先查看如下文章进行科普一下https://baike.baidu.com/item/AOP/1332219?fr=aladdin,再来阅读本文。示例前置准备注:本示例基于springboot进行演示1、在项目pom引入aop的GAV<dependency><groupId>or......
  • JS垃圾回收机制
    JS垃圾回收机制主要分为对栈和堆两种存储数据的回收:一、栈中数据回收1) 首先我们需要了解一个概念ESP指针:是指针寄存器的一种,用于堆栈指针,主要用来标记当前活动位置,简单就是标记当前代码执行位置2) 当我们执行一个函数时除了会有存储的变量外,还会有一个执行上下文;此......