Java的几种垃圾回收算法
上篇讲了在堆内存中,垃圾回收器是如何辨别哪些对象可以被回收,那么回收对象的时候又是怎么样的过程呢,本篇会介绍几个常见的垃圾回收算法
在Java中,垃圾回收的核心思想主要分为两部步:
- 通过上篇中的可达性算法找到存货的对象
- 释放不再存活的对象的内存,使得程序能再次利用这块空间,即回收
垃圾回收算法的效率
在Java中,垃圾回收的过程是单独创建了一个GC线程来完成,不管是哪种垃圾回收算法,在执行垃圾回收的时候都要先将用户线程停止,这个停止的过程称为STW:Stop The World,如果STW的时间过长则会影响用户的使用体验:
用户执行代码1 | STW | 用户执行代码2 | STW | 用户执行代码3 | … |
---|
所以判断一个垃圾回收算法是否优秀,可以从三个方面考虑:
- 吞吐量
吞吐量指的是CPU用于执行用户代码与CPU执行总时间的比值,即吞吐量=CPU执行用户代码时间 / 执行用户代码时间+GC时间
,吞吐量的值越高,垃圾回收的效率越高 - 最大暂停时间
即STW的最大值,程序暂停时间过长会降低用户体验感 - 堆使用效率
不同的垃圾回收算法对于堆的使用效率是不同的,如果对堆的使用效率越高,则需要垃圾回收的次数会越少
垃圾回收算法
目前共有四种常见的垃圾回收算法:
- 标记清除算法
- 复制算法
- 标记整理算法
- 分代垃圾回收算法
1.标记清除算法
标记清除算法的核心思想分为两类:
- 标记阶段:通过上篇讲述的可达性算法找到所有存活的对象,将其标记
- 清除阶段:将内存中的未标记存活对象进行清除回收
标记清除算法也是最早提出的垃圾回收算法,也是最简单的垃圾回收算法,首先会通过之前讲到的可达性算法,利用GC Root对象遍历引用,标记所有的存活对象,没有被GC Root找到的对象就是被认为已经不再使用的对象,则对其清除回收
红色对象是在标记阶段进行标记的对象,那么紫色对象就是没有被标记的,在清除阶段,对象D将会被回收
该方法的优点就是实现简单,并且对于堆的利用率比较高,但是缺点就是内存中会多很多碎片空间,堆内存中,需要进行回收的对象不一定是连续的,回收过后,空闲空间就会形成“这一块那一块”的情况,若是需要分配空间的话,就要遍历整个可用列表才能找到可用分配的空间
2.复制算法
复制算法把整个堆内存分为了两块:Form空间和To空间,但是这个名字不是定死的,因为在垃圾回收过程中名字会发生改变
他的过程主要分为两步:
- 把From空间所有的存活对象全部复制到To空间
- 清除From空间全部对象,再将两块空间进行交换名称
这样,我们创建的对象不管在那一片空间,在垃圾回收时,只要他还存活,就会被复制到To空间中,这样From空间中只剩下了要被回收的对象,清除回收From空间后呢,再进行交换名称,这样保证To空间的内存是完全充足的,等到下次垃圾回收时,以便再把From空间的存活对象复制过去
算法的优点是吞吐量高只需要遍历一次存活对象,并且也没有碎片空间,每次更名过后To空间都是一大片连续可用空间,但是他的缺点是堆使用效率不高
3.标记整理算法
标记整理算法是对于第一种算法标记清除算法的一种优化,他解决了清除过后碎片化空间的问题,他的大致过程为:
- 标记阶段:通过上篇讲述的可达性算法找到所有存活的对象,将其标记
- 整理阶段:把刚刚标记的对象全部移动到堆的一端,再进行清除操作
清除后存活的对象全部到了堆内存的一侧,而另一侧就是可用的空间,连续的空间在要为新对象分配内存时就可以依次为其分配,而不需要遍历可用列表寻找合适大小的空间的
该算法虽然解决了碎片化空间的问题,但是多次的遍历复制使其吞吐量大大降低
4.分代垃圾回收算法
分代垃圾回收算法,可以说是上面三种算法思想的组合,但是也与上面三种完全不同,他将堆内存分为了两个部分,一片是年轻代,另一片是老年代,而年轻代中又将其分为三片空间,伊甸园区、幸存区S0、幸存区S1
年轻代用来存放存活时间比较短的对象,老年代用来存放存活时间比较长的对象
新创建出来的对象会将他放在伊甸园区,而S0与S1来充当From区和To区的工作
该垃圾回收算法的大致过程如下:
- 当伊甸园区中新创建出来的对象越来越多,就会触发一次年轻代GC(Young GC),会先利用可达性算法找到存活的对象,然后再把伊甸园区和From区的存活对象复制到To区,并清除回收伊甸园区和From区,From与To进行更名操作
- 每次进行Young GC都会记录对象的年龄,年龄初始值为0,每GC一次就年龄+1,当一个对象的年龄达到15时,会认为他是一个长期存活对象,就把该对象复制移动到老年代区域
- 当老年代中空间即将饱和时,此时再有新的对象被创建,会先触发一次Young GC,如果依然空间不足,就会触发Full GC,会对整个堆内存进行垃圾回收,回收一部分老年代中的对象
目前较新的垃圾回收器使用的都是分代垃圾回收算法