①标记清除算法、复制算法、标记整理算法、分代回收算法。
第一个标记清除算法,它首先会从根对象开始进行可达性分析,标记出所有和根对象直接或间接关联的对象,然后在标记完成后会统一回收所有没有被标记的对象。标记清除算法是最基础的垃圾回收算法,缺点也很明显,一个是标记和清除这两个过程的效率都比较低,另一个是会导致内存空间碎片化,而后续的算法都是在它的基础上进行改进得到的。
第二个复制算法,它是将某块内存分为两块,分别叫做From区和To区,新创建的对象会被分配分在From区中,From区满了就会进行垃圾回收,将From区中存活的对象复制到To区中,然后清空From区。之后再交换两块内存的角色,原先的From区变为To区,原先的To区变为From区。复制算法的优点是简单高效,解决了标记清除算法的内存碎片化问题,缺点是内存空间利用率低,适用于频繁进行垃圾回收并且一次垃圾回收就会死去很多对象的内存区域,比如新生代。
第三个标记整理算法,它首先也会从根对象开始进行可达性分析,标记出所有和根对象直接或间接关联的对象,然后在标记完成后会将存活的对象紧凑地移动到内存的一端,然后直接清空剩余的内存空间。标记整理算法解决了标记清除算法的内存碎片化问题,但效率仍然较低,适用于垃圾回收频率较低的内存区域,比如老年代。
第四个分代回收算法,它根据对象的存活周期将内存划分为不同的几块,然后对不同的内存区域使用不同的垃圾回收算法,比如在新生代中使用复制算法,在老年代中使用标记整理算法。
详细讲下分代回收算法?
在java8中,堆内存被分为了新生代和老年代,它俩默认的空间占用比例是1 : 2。新生代又被分为了伊甸区和两个幸存者区s0、s1,它们三个默认的空间占用比例是8 : 1 : 1。
新创建的对象会优先被分配到伊甸区中,当伊甸区空间不足时就会触发MinorGC,将伊甸区和s0区中存活的对象复制到s1区中,然后对象年龄加1并清空伊甸区和s0区。当又一次触发MinorGC时,会将伊甸区和s1区中的对象复制到s0区中,然后对象年龄加1并清空伊甸区和s1区。
它就是以这种方式循环的,默认情况下,当对象的年龄达到15岁时,这个对象就会被移入到老年代中。不过也有特殊情况,比如创建的是一个比较大的对象,那么这个对象会被直接分配到老年代中,当老年代空间不足时就会触发MajorGC。
②Minor GC是对新生代进行垃圾回收的过程,当伊甸区空间不足时会触发Minor GC。
Major GC是对老年代进行垃圾回收的过程,当老年代空间不足时会触发Major GC。
Full GC是对整个堆内存和方法区进行垃圾回收的过程,在发生Minor GC之前,如果老年代中最大可用的连续空间小于新生代中所有对象占用的空间(空间分配担保失败),那么就会触发Full GC。还有就是JDK1.7中如果永久代满了也会触发Full GC。
③JVM提供了很多种垃圾回收器,其中Serial、ParNew、Parallel Scavenge是作用于新生代的垃圾回收器,Serial Old、Paralled Old、CMS是作用于老年代的垃圾回收器,G1是同时作于于新生代和老年代用于整堆收集的垃圾回收器。JDK1.8中默认的垃圾回收器是Parallel Scavenge和Paralled Old配合使用,从JDK1.9开始默认的默认的垃圾回收器是G1。
CMS是一款作用于老年代上的并发垃圾回收器,主要目标是尽量减少垃圾回收时用户线程的暂停时间。它采用了标记整理算法,工作过程分为初始标记、并发标记、重新标记、并发清除4个阶段。
在初始标记阶段会暂停所有用户线程,然后使用一个GC线程标记出根对象还有和根对象直接关联的对象,这个过程速度很快。在并发标记阶段会开启用户线程,用户线程可以和GC线程一起并发运行,GC线程会并发标记出所有可达对象,但由于用户线程会不断的更新引用域,所以GC线程不能保证可达性分析的实时性,这个过程的停顿时间较长。在重新标记阶段会再次暂停所有用户线程,然后使用GC线程修正在并发标记期间发生的引用变化并标记新的对象,这个过程的停顿时间比初始标记阶段稍长一些,但远远小于并发标记阶段的时间。在并发清除阶段会再次开启用户线程,同时GC线程会清除未被标记的对象。
G1是一款作用于整堆上的并发垃圾回收器,主要针对具有多核处理器和大容量内存的服务器,它的主要目标在延迟可控的情况下获得尽可能高的吞吐量。它将Java堆划分为多个大小相同的区域,每个区域都可以作为伊甸区、幸存者区或老年代。它采用的是标记复制算法,工作过程分为初始标记、并发标记、最终标记、筛选回收4个阶段。
在初始标记阶段会暂停所有用户线程,然后使用一个GC线程标记出根对象还有和根对象直接关联的对象,这个过程速度很快。在并发标记阶段会开启用户线程,用户线程可以和GC线程一起并发运行,GC线程会并发标记出所有可达对象,但由于用户线程会不断的更新引用域,所以GC线程不能保证可达性分析的实时性,这个过程的停顿时间较长。在最终标记阶段会再次暂停所有用户线程,然后使用GC线程修正在并发标记期间发生的引用变化并标记新的对象,这个过程的停顿时间比初始标记阶段稍长一些,但远远小于并发标记阶段的时间。在筛选回收阶段,G1会根据允许的回收时间,优先选择回收价值最大的区域,也就是存活对象最小的区域,然后将这些区域中存活的对象复制到另一个区域中,这种回收方式保证了G1能在有限时间内尽可能地腾出更多内存空间。回收完成后会开启用户线程。