您当前的位置:首页 > 电脑百科 > 程序开发 > 算法

聊聊垃圾回收算法

时间:2021-09-24 13:42:15  来源:  作者:支持者也之乎

其实,对于写代码来说,也有垃圾回收这个问题,这里所说的垃圾,指的是程序中不再需要的内存空间,垃圾回收指的是回收这些不再需要的内存空间,让程序可以重新利用这些释放的内存空间。

 

那么垃圾回收是怎么,是不采用算法来实现呢?本次课时,我们就一起来探讨 JAVA 的垃圾回收算法。

 

标记-清除算法(Mark-Sweep)

 

标记-清除,顾名思义,先标记垃圾,再清除。它是垃圾回收最基础的算法,后续很多算法都是基于它上面去改进的。标记-清除算法主要分成两个阶段:

 

标记阶段:需要回收的对象。那么这个过程其实就是使用可达性分析去判断一个对象是不是垃圾的过程。

 

清除阶段:标记完成之后,就会统一清理掉要回收的对象。

 

用图表示出来大致如下图所示:

聊聊垃圾回收算法

 

先去标记哪些对象是存活的,哪些对象是可以回收的。标记完成之后把它回收的对象直接删掉。从这张图可以看出来。标记清除它存在一定的缺点,标记清除后会产生大量不连续的内存碎片,空间碎片太多可能会导致程序在运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。比如现在假设我们想在内存里面分配一段连续三个单位的内存空间,要分配一个超大的字节数组,在这样的内存结构下就没有办法做到了。

 

标记-整理算法(Mark-compact)

 

下面来看一下做标记-整理算法,也有一些文章会把它翻译成标记-压缩,本课程里面统一称作是标记-整理算法,那么标记-整理算法是怎玩的。

 

首先也是标记要回收的对象,这个过程和标记清除是一样的,但是在标记完成之后并不是直接清除掉要回收的对象,而是把所有的存活对象都压缩到内存的一端,最后在清理掉边界之外的所有空间,所以不会产生内存碎片,提高了内存的利用率,这种算法适用于老年代。用图表示出来大概如下图所示:

 

聊聊垃圾回收算法

先去标记哪些对象是存活的,哪些对象可以回收,然后把存活的对象往内存的一端压缩,最后再把可以回收的对象除清除。这样就可以避免内存碎片的问题,但是这种方式在标记和整理移动的过程中也是耗时的。

 

复制算法(Copy)

 

复制算法大致上是这样玩的,把内存分成两块,每次只使用其中的一块,然后把正在使用的这块内存里面的存活对象复制到不使用的内存里面去,然后再清理掉正在使用的这块内存里面的所有对象,接着交换两块内存的角色,等待下一次回收。用图表示大概如下图所示:

聊聊垃圾回收算法

 

把一块内存分成了两块,每次只使用其中的一块,在做垃圾回收的时候,把存活的对象移动到另外一端内存里面去,然后清除掉这块内存里面的所有对象。那么在下一次回收的时候也是一样,把存活的对象移动回来,然后清除掉这一块内存里面的所有对象。

 

三种算法对比

 

以上是三种比较基础的垃圾回收算法,下面来对比一下这三种算法。

 

标记-清除算法的优点:实现起来比较简单。

 

缺点:存在内存碎片。另外使用标记清除算法的时候,分配内存的速度也会受到影响,这是为什么呢?你想,假设现在有一个比较大的对象,因为现在有很多碎片化的内存空间。那么想找到一块连续空间的话,就需要去便利空闲链表,从而值查找哪一块内存可以存放这样的对象。那么在极端场景下,需要把整个链表全部遍历完,才能知道这个对象该分配到哪里去,又或者根本没有办法分配。那么遍历空闲链表是需要时间的,所以分配内存的速度会受到影响。

 

标记-整理算法的优点:没有碎片。

 

缺点:整理存在开销。因为标记整理需要把对象集中起来,放到内存的一端,这个过程需要计算以及时间,并且对象越多,占的内存越大,整理的开销也会越大。

 

复制算法的优点是性能好,没有碎片。一般来讲复制算法比标记-清除算法以及标记-整理算法性能要好一些,因为它不像标记-清除算法或者标记-整理算法那样,需要标记哪些对象是存活的,哪些对象可以回收,而只需要找到存活的对象。然后移动这个存活的对象。所以性能上会有一些优势。

 

缺点:内存使用率低。我们一次只能使用整个内存的一半,内存使用率最多只会达到 50%。

 

两种综合的算法

 

好,探讨完三种基础的垃圾回收算法之后,再来探讨 Java 里面两种相对综合的垃圾回收算法。

 

第一种是分代收集算法。分代收集算法的思路是把一个内存分成多个区域,不同的区域使用不同的回收算法去回收。代收集算法比较复杂,而且细节极其之多。我们将在下面详细讨论。

 

第二种是增量算法。你想,如果你的内存非常的大,如果一次收集所有垃圾,那么需要耗费的时间就会比较的长,有可能会造成系统长时间的停顿。那么增量算法的思想是每次只收集一小片区域内存空间的垃圾,这样就可以减少系统的停顿。

 

分代收集算法

 

目前各种商业虚拟机,它的堆内存的回收基本上都采用了分代收集的方式。所以可想而知,分代收集算法有多么重要。

 

现在设计算法的思想是根据对象的存活周期,把内存分成多个区域,然后不同的区域使用不同的垃圾回收算法去回收对象。Java 把堆分成了新生代和老年代。下图前面探讨 Java 内存结构的时候已经详细介绍过了。

聊聊垃圾回收算法

 

那么经过分代之后啊,垃圾回收可以分成以下几类:

 

一是新生代的回收(Minor GC 或者 Young GC)。

 

二是老年代的回收(Major GC)。

 

三是整个堆的回收(Full GC)。

 

那么由于执行 Major GC 的时候,一般也会伴随着一次 Minor GC,所以可以认为 Major GC ≈ Full GC 。那么很多时候,程序员在聊 Major GC 以及 Full GC 的时候,聊的就是一件事儿。

 

下面来看一下对象是怎么样分配到堆内存的,我们还是对照堆内存的结构去讲解。对象在创建的时候会先存放到 Eden。当 Eden 满了之后就会触发垃圾回收,这个回收的过程是把 Eden 里面存活的对象拷贝的存活区里面的 From Survivor 或者是 To Survivor 里面去。

 

比如第一次回收 From Survivor 里面去了,那么下一次回收就会把 From Survivor 里面存活的对象拷贝到 To Survivor 里面去,再下一次就会把 From Survivor 面里面存活的对象拷贝的 From Survivor 里面去,周而复始。

 

不难发现这个回收的过程使用了复制算法,这也是为什么新生代要有两个 Survivor 的原因。因为复制算法需要把一个内存分成两块。那么对象每经历一次垃圾回收之后,如果还存活的话,它的年龄就会增加 +1。当对象的年龄达到阈值的话,默认情况下是 15,就会晋升到老年代。

 

老年代里面的对象存活率一般是比较高的,因为你想,都回收 15 次了,还是没能回收得了,所以后面继续存活的可能性依然是比较大的。

 

那么老年代的对象一般会使用标记-清除算法或者是标记-整理算法去进行回收。这里需要说明一下,这个对象分配的过程只是一个典型的分配流程,实际情况是存在例外的:

 

一是,一个新建对象,并利率总是会分配到 Eden,也可能会直接进入到老年代。主要有两种场景。第一,如果你的对象大小,大于这个阈值就会直接分配到老年代。当然了,默认情况下这个参数的值是零,也就是说不做限制,所有的对象都会优先在 Eden 里面分配。第二,如果你的对象非常的大,比方说一个超大的数组,新生代的空间根本都不够,那么这个时候也会直接把这个对象放到老年代去担保。之所以要允许对象直接分配到老年代,主要是因为新生代采用的是复制算法,在 Eden 里面分配大对象的话,将会导致 Eden 和两个 Survivor 区之间大量的内存拷贝。

 

二是,对象也不一定要达到年龄阈值,才会进入到老年代。虚拟机有一个动态年龄的概念,就是说如果存活区里面,所有相同年龄对象的大小的总和已经大于 Survivor 空间的一半了。这个时候,如果某个对象的年龄大于这个年龄的话,会直接进入老年代,比如有一堆的对象,它的年龄值是 9,年龄都是 9 的所有对象它的总和以及大于 Survivor 空间的一半了,那么年龄大于 9 的对象就会直接进入老年代。

 

触发垃圾回收的条件

 

下面我们来看一下不同区域触发垃圾回收的条件:

 

先来看一下新生代回收的触发条件,Eden 空间不足就会进行 Minor GC 回收新生代。

 

再来看一下 Full GC 的触发条件,Full GC 的触发条件要复杂一些,主要有这么几种场景:

 

一是,老年代空间不足,老年代代空间不足又分为两种情况:第一是空间真的不足了。第二是内存碎片,导致没有连续的内存去分配对象,触发 Full GC。

 

二是,元空间不足。

 

三是,在某一次新生代回收之后,要晋升到老年代的对象所占用的空间大于了老年代的剩余空间,这个时候也会触发 Full GG。

 

四是,显式调用了 System.gc()。System.gc() 的作用是建议垃圾回收容器直径垃圾回收,这个代码是会触发 Full GC 的,你也可以使用这个参数:-XX:DisableExplicitGC 去忽略掉 System.gc() 的调用。

 

好,介绍到这里可以简单总结一下,分代收集算法是根据对象的生命周期,把内存做的分代。然后在分配对象的时候,把不同生命周期的对象放在不同代里面,不同的代上选用合适的回收算法进行回收。

 

比如,新生代里面的对象存活周期一般都比较的短,每次垃圾回收的时候都会发现有大量的对象死去。那么 IBM 有做过研究,98% 以上的对象都是会很快消亡的,只有少量的对象能够存活,所以新生代可以使用复制算法来完成垃圾收集。而老年代里面的对象存活率比较高,所以就采用标记-清除算法或者是标记-整理算法进行回收。

 

那么相比单纯的标记-清除算法、标记-整理算方法以及复制算法三代带来了什么好处呢?

 

首先,分代可以更有效的清除不需要的对象,对于生命周期比较短的对象,对象还处于新生代的时候就会被回收掉了。

 

其次,分代提升的垃圾回收的效率。如果不做分代的话,那么需要扫描整个堆里面的对象。而现在的话只要扫描新生代或者老年代就可以了。

 

总结

 

好,简单总结一下,本课时课我们探讨了五种垃圾口的算法。基础的垃圾回收算法有标记-清除算法、标记-整理以及复制算法。另外还探讨了两种综合性的垃圾回收算法,即分代收集算法以及增量算法,同时详细探讨分代收集算法。

 

最后来总结一下分代收集算法的调优原则:

 

第一,要合理的设置 Survivor 区的大小,因为 Survivor 区对内存的利用率不高。如果配置的过大的话,内存浪费就会比较严重。

 

第二,要让 GC 尽量的发生在新生代,也就是让 GC 停留在 Minor GC 的级别。

尽量减少 Full GC 的发生。

 

另外,总结有关堆内存的 JVM 参数。

 

参数 作用 默认
-XX:NewRatio=n 老年代:新生代内存大小比值 2
-XX:SurvivorRatio=n 伊甸园:survivor区内存大小比值 8
-XX:PretenureSizeThreshold=n 对象大小该值就在老年代分配,0表示不做限制 0
-Xms 需小堆内存 -
-Xmx 最大堆内存 -
-Xmn 新生代大小 -
-XX:+DisableExplicitGC 忽略掉 System.gc() 的调用 启用
-XX:NewSize=n 新生代初始内存大小 -
-XX:MaxNewSize=n 新生代最大内存 -

 



Tags:算法   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
前言Kafka 中有很多延时操作,比如对于耗时的网络请求(比如 Produce 是等待 ISR 副本复制成功)会被封装成 DelayOperation 进行延迟处理操作,防止阻塞 Kafka请求处理线程。Kafka...【详细内容】
2021-12-27  Tags: 算法  点击:(1)  评论:(0)  加入收藏
分稀疏重建和稠密重建两类:稀疏重建:使用RGB相机SLAMOrb-slam,Orb-slam2,orb-slam3:工程地址在: http://webdiis.unizar.es/~raulmur/orbslam/ DSO(Direct Sparse Odometry)因为...【详细内容】
2021-12-23  Tags: 算法  点击:(7)  评论:(0)  加入收藏
一、什么是冒泡排序1.1、文字描述冒泡排序是一种简单的排序算法。它重复地走访要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地...【详细内容】
2021-12-15  Tags: 算法  点击:(16)  评论:(0)  加入收藏
前面文章在谈论分布式唯一ID生成的时候,有提到雪花算法,这一次,我们详细点讲解,只讲它。SnowFlake算法据国家大气研究中心的查尔斯·奈特称,一般的雪花大约由10^19个水分子...【详细内容】
2021-11-17  Tags: 算法  点击:(24)  评论:(0)  加入收藏
基于算法的业务或者说AI的应用在这几年发展得很快。但是,在实际应用的场景中,我们经常会遇到一些非常奇怪的偏差现象。例如,Facebook将黑人标记为灵长类动物、城市图像识别系统...【详细内容】
2021-11-08  Tags: 算法  点击:(32)  评论:(0)  加入收藏
随着注册制的加速推进,新股越来越多,截止到今天A股上市公司的总数高达4500余家,A股一直就是重融资,轻投资的市场,而上市公司发行可转债这种再融资的(圈钱方式)是最能让普通投资者接...【详细内容】
2021-11-05  Tags: 算法  点击:(97)  评论:(0)  加入收藏
导读:在大数据时代,对复杂数据结构中的各数据项进行有效的排序和查找的能力非常重要,因为很多现代算法都需要用到它。在为数据恰当选择排序和查找策略时,需要根据数据的规模和类型进行判断。尽管不同策略最终得到的结果完...【详细内容】
2021-11-04  Tags: 算法  点击:(37)  评论:(0)  加入收藏
这是我在网上找的资源的一个总结,会先给出一个我看了觉得还行的关于算法的讲解,再配上实现的代码: Original author: Bill_Hoo Original Address: http://blog.sina.com.cn/s/bl...【详细内容】
2021-11-04  Tags: 算法  点击:(36)  评论:(0)  加入收藏
每个人都有过这样的经历:打开手机准备回消息或打电话,一看到微信图标右上方的小红点,于是忍不住先打开微信;看完微信,不知不觉又被另一个App牵引,直到关闭手机屏幕才发现自己早已...【详细内容】
2021-11-03  Tags: 算法  点击:(30)  评论:(0)  加入收藏
文丨互联网怪盗团在互联网行业,尤其是在投资人心目中,往往存在一种“算法迷信”或曰“技术迷信”:某公司的广告变现做得好,一定是因为有算法;某公司的云计算业务开展的好,也是因为...【详细内容】
2021-11-03  Tags: 算法  点击:(25)  评论:(0)  加入收藏
▌简易百科推荐
前言Kafka 中有很多延时操作,比如对于耗时的网络请求(比如 Produce 是等待 ISR 副本复制成功)会被封装成 DelayOperation 进行延迟处理操作,防止阻塞 Kafka请求处理线程。Kafka...【详细内容】
2021-12-27  Java技术那些事    Tags:时间轮   点击:(1)  评论:(0)  加入收藏
博雯 发自 凹非寺量子位 报道 | 公众号 QbitAI在炼丹过程中,为了减少训练所需资源,MLer有时会将大型复杂的大模型“蒸馏”为较小的模型,同时还要保证与压缩前相当的结果。这就...【详细内容】
2021-12-24  量子位    Tags:蒸馏法   点击:(9)  评论:(0)  加入收藏
分稀疏重建和稠密重建两类:稀疏重建:使用RGB相机SLAMOrb-slam,Orb-slam2,orb-slam3:工程地址在: http://webdiis.unizar.es/~raulmur/orbslam/ DSO(Direct Sparse Odometry)因为...【详细内容】
2021-12-23  老师明明可以靠颜值    Tags:算法   点击:(7)  评论:(0)  加入收藏
1. 基本概念希尔排序又叫递减增量排序算法,它是在直接插入排序算法的基础上进行改进而来的,综合来说它的效率肯定是要高于直接插入排序算法的;希尔排序是一种不稳定的排序算法...【详细内容】
2021-12-22  青石野草    Tags:希尔排序   点击:(6)  评论:(0)  加入收藏
ROP是一种技巧,我们对execve函数进行拼凑来进行system /bin/sh。栈迁移的特征是溢出0x10个字符,在本次getshell中,还碰到了如何利用printf函数来进行canary的泄露。ROP+栈迁移...【详细内容】
2021-12-15  星云博创    Tags:栈迁移   点击:(19)  评论:(0)  加入收藏
一、什么是冒泡排序1.1、文字描述冒泡排序是一种简单的排序算法。它重复地走访要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地...【详细内容】
2021-12-15    晓掌柜丶韶华  Tags:排序算法   点击:(16)  评论:(0)  加入收藏
在了解golang的map之前,我们需要了解哈希这个概念。哈希表,又称散列表(Hash table),是根据键(key)而直接访问在内存储存位置的数据结构。也就是说,它通过计算出一个键值的函数,将...【详细内容】
2021-12-07  一棵梧桐木    Tags:哈希表   点击:(13)  评论:(0)  加入收藏
前面文章在谈论分布式唯一ID生成的时候,有提到雪花算法,这一次,我们详细点讲解,只讲它。SnowFlake算法据国家大气研究中心的查尔斯·奈特称,一般的雪花大约由10^19个水分子...【详细内容】
2021-11-17  小心程序猿QAQ    Tags:雪花算法   点击:(24)  评论:(0)  加入收藏
导读:在大数据时代,对复杂数据结构中的各数据项进行有效的排序和查找的能力非常重要,因为很多现代算法都需要用到它。在为数据恰当选择排序和查找策略时,需要根据数据的规模和类型进行判断。尽管不同策略最终得到的结果完...【详细内容】
2021-11-04  华章科技    Tags:排序算法   点击:(37)  评论:(0)  加入收藏
这是我在网上找的资源的一个总结,会先给出一个我看了觉得还行的关于算法的讲解,再配上实现的代码: Original author: Bill_Hoo Original Address: http://blog.sina.com.cn/s/bl...【详细内容】
2021-11-04  有AI野心的电工和码农    Tags: KMP算法   点击:(36)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条