JVM垃圾收集之二:垃圾收集算法

目录

概述

垃圾收集算法

1. 分代收集理论

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

3. 标记-复制算法(Mark-Copy)

4. 标记-整理算法(Mark-Compact)

5. 分代收集之算法选择

6. 垃圾收集算法评价标准

        6.1 吞吐量

        6.2 最大暂停时间

        6.3 堆使用效率

        6.4 评价(个人总结)


概述

        在上一篇《什么是垃圾》JVM垃圾收集之:什么是垃圾?-CSDN博客 中我们已经讲到,使用引用计数法和可达性分析算法两种方法来判断对象是不是垃圾,那么在已经明确垃圾后,我们就可以开始着手收集和回收,垃圾的收集和回收有几套算法,以及在垃圾收集算法的基础上实现的几种垃圾回收器。今天我们重点讲垃圾收集算法。

垃圾收集算法

1. 分代收集理论

        分代收集理论简单的说,就是将堆内存物理分割为两个区块,一块用来分配新创建的对象,一块用来分配经过多次垃圾收集过程还存活的老年对象,分配新对象的区块被称为新生代,分配老年对象的区块被称为老年代。

        分代收集理论是一套符合大多数程序运行实际情况的经验法则,它建立在两条经验(亦称为假说)上:

                1,绝大多数对象都是朝生夕灭的。

                2,熬过越多次垃圾收集过程的对象就越难以消亡。

        经验1和经验2分别描述了两种类型的对象,1)朝生夕灭的,2)年龄越活越大的,1)2)占了很大比例,当然也有其他类型,比如年龄活的不大不小的,但是比例很小(年龄即对象熬过垃圾收集过程的次数),所以将堆根据两类对象划分年轻代老年代两个区域,然后在不同分区,根据对象的存亡特点安排对应的回收算法以更高效的回收垃圾——因而发展出了标记-清除算法标记-复制算法标记-整理算法等针对性的垃圾收集法。

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

        标记-清除算法是最早出现也是最基础的垃圾收集算法,符合人们日常思维习惯:发现垃圾,清除垃圾。 算法分为“标记”和“清除”两个阶段:首先可达性分析算法标记出存活对象,然后统一回收所有未被标记的对象。

        标记-清除算法的优点:简单

        标记-清除算法的缺点:

                1,标记和清除操作会扫描整个空间两次(第一次:标记存活对象; 第二次:清除没有标记的对象)才能完成清理工作,当内存有大量对象时,效率较低。

                2,清理阶段容易产生内存碎片,碎片空间无法容纳大对象,如果此时有一个比较大的对象进入内存,由于该内存中没有连续的空间容纳大对象,就会提前触发垃圾回收。如下图所示未使用的空间形成不连续的空间碎片。

3. 标记-复制算法(Mark-Copy)

        标记-复制算法常被简称为复制算法,也称为“半区复制”(Semispace Copying)的垃圾收集算法。该算法分两个阶段:标记阶段复制阶段。它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,进入标记阶段,标记存活的对象;然后进入复制阶段,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉,如此往复循环。

        标记-复制算法的优点:

                大部分时候高效,因为IBM公司曾有一项专门研究对新生代“朝生夕灭”的特点做了更量化的诠释--新生代中的对象有98%熬不过第一轮收集,复制算法每次只需要拷贝存活的对象,很高效。如果程序里对象存活比例很大,复制算法的效率将会降低。所以复制算法非常适合在年轻代使用!不适合老年代使用!

                不会产生内存碎片,因为每次拷贝存活对象后都是将对象按顺序排放。

        标记-复制算法的缺点:

                内存利用率太低,很明显,每次只能利用一半的内存。

4. 标记-整理算法(Mark-Compact)

        标记-整理算法也称为标记-压缩算法,该算法解决了标记-清除算法会产生内存碎片的问题(将碎片整理或压缩,变成连续可用内存空间)。该算法分为“标记”和“整理”两个阶段,标记:使用可达性分析算法标记出标记存活的对象,整理:让所有存活的对象都向内存空间一端移动,然后直接清理掉边界以外的内存。而不是想标记-清除算法直接对可回收对象进行清理。如图所示:

        标记-整理算法的优点:

                和标记-清除比较,没有垃圾碎片产生。

                和标记-复制比较,内存利用率高一倍。

        标记-整理算法的缺点:

                整理阶段效率不高,需要移动对象,并且更新这些对象的引用地址,这是一种极为负重的操作,且这种对象移动操作必须全程暂停用户应用程序才能进行,也就是有名的STW(Stop The World)。

5. 分代收集之算法选择

        分代收集理论中将堆内存分为新生代和老年代,而不同代所分配的对象特别不同,新生代对象朝生夕灭,98%活不过第一轮的垃圾收集过程,老年代对象是经过多次的垃圾回收过程还能存活的对象,所以不同代的垃圾回收算法也不同。

        新生代:对象存活率很低,使用标记-复制算法效率高,而且不会产生内存碎片。

        老年代:对象存活率高,标记复制算法非常不合适,可以用标记-清除算法或标记-整理算法,亦或一起用

6. 垃圾收集算法评价标准

        垃圾回收经常会遇到一个概念STW(Stop The World),在垃圾收集过程中发生STW是指:垃圾收集过程中全部用户线程全程停止,就好像世界被停止了一样,STW结束后,用户线程会继续运行。

        6.1 吞吐量

                吞吐量指的是 CPU 用于执行用户代码的时间与 CPU 总执行时间的比值,即吞吐量 = 执行用户代码时间 / (执行用户代码时间 + GC时间)。吞吐量数值越高,垃圾回收的效率就越高,程序执行的效率也越高。

        吞吐量 = 32*3/(32*3+1+3) = 96/100 = 96%

        6.2 最大暂停时间

                最大暂停时间指的是所有在垃圾回收过程中的STW时间最大值。最大暂停时间越短,用户使用系统时受 到的影响就越短。

        最大暂停时间:3s

        6.3 堆使用效率

                不同垃圾回收算法,对堆内存的使用方式是不同的。标记清除算法:100%。复制算法:50%。

        6.4 评价(个人总结)

                知道了以上评价标准,我们可以更客观地评价一个算法,也能理解垃圾收集器为什么选择某个算法。

                评价1,移动对象,需要更新这些对象的引用地址,必须STW,在标记-复制算法的复制阶段,标记-整 理的整理阶段,都需要STW

                评价2,标记-清除算法,是比较原始算法,垃圾收集过程都会STW,该算法最大暂停时间指标会较高

                评价3,标记-整理算法和标记-清除相比,两个算法都有相同的标记阶段,删除垃圾阶段,如果面对相同 清理对象,它们在标记阶段,删除垃圾阶段的耗时应该是差不多的,但标记-整理算法在标记完后需要整理,1 中我们知道移动对象是需要STW的,所以标记-整理算法是需要比标记-清除算法多出额外STW时间,也就是 最大暂停时间指标会更高一点

                在【5.分代收集之算法选择】中已经讲过,老年代有两种算法可选,分别是标记-清除算法和标记-整理算 法,评价3已经得出结论:标记-整理算法是需要比标记-清除算法最大暂停时间指标会更高一点,CMS垃圾收 集器更关注延迟,所以在老年代选择标记-清除算法。

                评价4,标记-整理算法和标记-清除相比,谁的吞吐量更高呢?我们知道标记-整理算法的STW是高于标 记-清除算法的,GC阶段暂停会更久,按照吞吐量的公式计算:吞吐量 = 执行用户代码时间 /(执行用户代码 时间 + GC时间),标记-整理的吞吐量应该小于标记-清除的吞吐量。但是《深入理解java虚拟机》3.3.4章节 中却提到一点,标记-清除算法产生的垃圾碎片,解决空间碎片化问题就只能依赖更为复杂的内存分配器和内 存访问器,但因内存分配和访问相比垃圾收集频率要高得多,这部分的耗时增加,类似于GC的STW的增加, 虽然标记-清除算法STW时间短,但是总吞吐量仍然是下降的,Parallel Scavenge收集器关注吞吐量,所 以老年代选择基于标记-整理算法

参考:JVM基础篇:垃圾回收-CSDN博客

书籍:深入理解Java虚拟机:JVM高级特性…佳实践(第3版)周志明。

声明:侵权必删,本文无任何功利,给知识传播多一扇窗。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值