作为一名JAVA程序员,一般面试的时候最常准备的面试题就是JVM垃圾回收(GC)机制了。一般人都会知道,在开发过程中,会创建很多对象,这些对象都会存在于JVM内存模型的堆中,这样下去,堆空间很快就会被耗尽,所以JVM提供了垃圾回收机制,用于将一些没用的对象清理掉。
那么,JVM是怎么判断哪些对象是垃圾,又是怎么回收的呢?这就需要了解今天我们要讨论的主题,JVM的垃圾回收算法了。
那么,垃圾回收有几种算法呢?通常来说,JVM的垃圾回收算法一共有以下几种。
一、串行GC(Serial GC)
串行GC是很简单的一种GC算法,它对年轻代使用 mark-copy(标记-复制) 算法,对老年代使用 mark-sweep-compact(标记-清除-整理)算法。而这两者都是单线程的垃圾收集器,并不能进行并行处理。因此,两者都会触发全线暂停(stop the world, STM),停止所有的应用线程。因此这种GC算法不能充分利用多核CPU。不管有多少CPU内核, JVM 在垃圾收集时都只能使用单个核心。
所以这种算法只适合于几面MB堆内存的JVM,在单核CPU的情况下使用。它的JVM参数配置如下:
java -XX:+UseSerialGC
二、并行GC(Parallel GC)
相对于串行GC而言,顾名思义,并行GC可以通过并行执行来减少GC时间,其使用的算法和串行GC一样,也是对年轻代使用 mark-copy(标记-复制) 算法,对老年代使用 mark-sweep-compact(标记-清除-整理)算法,但是在标记和复制/整理阶段都会使用多个线程。因此适用于多核处理器。它的JVM参数配置可以使用-XX:+UseParallelGC 或-XX:+UseParallelOldGC
三、CMS GC (Concurrent Mark Sweep GC)
CMS算法与以上两种算法一样,也是面向分代的垃圾回收算法,主要面向老年代进行垃圾收集,其尝试通过使用单独的垃圾收集器线程在执行应用程序线程的同时执行并跟踪可访问对象,来减少由于主要收集而导致的暂停时间。在并发标记阶段,CMS GC会把发生变化的对象所在的Card标识为Dirty,这样后续就只需要扫描这些Dirty Card的对象,从而避免扫描整个老年代。这样,就达到了减少应用停顿时间的目的。
CMS的问题在于堆内存碎片化问题无法得到解决,因此,JVM有可能会触发Full GC来进行碎片整理。
CMS GC的参数配置如下:
-XX:+UseConcMarkSweepGC
四、G1 GC
为克服CMS GC的缺点,在JDK1.7中引入了G1 GC,G1 GC在并发回收的同时,会对对象进行适合的移动,有效的复制对象,从而减少空间碎片的产生。在G1 GC中,如果清除步骤发现所有的区别都是由可回收垃圾组成的,则会立即回收这些空间,并且将这些空间插入到一个LinkedList实现的空闲队列里,这一特点也是G1 GC和其它GC的最大差别。
但是在一些特殊情况下,G1 GC可能会增加Java堆的尺寸。例如在Full GC中,基于堆尺寸的计算结果会调整堆的空间。或者在一个对象分配失败的时候,G1会尝试增加堆尺寸来满足对象分配等。
G1 GC涉及到的JVM参数如下,从JAVA 9开始,G1 GC是默认的GC算法,此前并行GC是默认算法:
-XX:UseG1GC
-XX:G1HeapRegionSize
-XX:G1MaxNewSizePercent
-XX:G1NewSizePercent
-XX:MaxGCPauseMillis
-XX:ConcGCThreads
-XX:ParallelGCThreads
-XX:G1MixedGCLiveThresholdPercent
-XX:InitiatingHeapOccupancyPercent
-XX:G1HeapWastePercent
-XX:G1OldCSetRegionThresholdPercent
-XX:G1MixedGCCountTarget
-XX:G1ReservePercent
-XX:MaxTenuringThreshold
五、Shenandoah GC
JDK12开始引入了Shenandoah GC,它的主要目标是使99.9%的停顿小于10ms,这种算法与其它GC算法的主要区别是引入了一个Concurrent Evacuation的过程,在这一过程中,JVM将对象集合从集合集复制到其它区别。
它的JVM参数配置如下:
-XX:+UseShenandoahGC
六、Z GC
Z GC据说与Azul的Zing 中的C4 GC是完全等价的,这是一款性能比G1优秀的垃圾收集器,在JDK11中,Z GC被以实验性的特性引入,在JDK15中正式投入使用。在JDK16发布后,GC暂停时间已经缩小到1ms以内,并且时间复杂度为o(1)了,这也意味着GC停顿时间是一个固定值,不会受到堆内存大小的影响了。
在Z GC中,为了更灵活高效的管理内存,使用了内存多重映射,把同一块儿物理内存映射为Marked0、Marked1、Remapped三个虚拟内存。当应用程序创建对象时,会在堆上申请一个虚拟地址,这时 ZGC 会为这个对象在 Marked0、Marked1 和 Remapped 这三个视图空间分别申请一个虚拟地址,这三个虚拟地址映射到同一个物理地址。Marked0、Marked1 和 Remapped 这三个虚拟内存作为 ZGC 的三个视图空间,在同一个时间点内只能有一个有效。ZGC 就是通过这三个视图空间的切换,来完成并发的垃圾回收。
它的JVM参数配置如下:
-XX:+UseZGC
七、Epsilon GC
区别与其它GC,与Z GC一起在JDK11中被引入的Epsilon GC是A NoOp Garbage Collector(没有操作的垃圾收集器)。JDK上对这个特性的描述是:开发一个处理内存分配但不实现任何实际内存回收机制的GC, 一旦可用堆内存用完,JVM就会退出。也就是说,这是一个没有什么卵用的GC。它的作用主要在于进行性能测试,它可以有效的过滤掉GC对于性能的影响,因为它什么也不做。另外它也可以用于进行内存压力测试,看看多久程序会崩溃,用于检测自己的代码质量。
它的JVM参数配置如下:
-XX:+UseEpsilonGC
还没有评论,来说两句吧...