JVM 有哪些垃圾回收器?
图中展示了7种作用于不同分代的收集器,如果两个收集器之间存在连线,则说明它们可以搭配使用。虚拟机所处的区域则表示它是属于新生代还是老年代收集器。
新生代收集器(全部的都是复制算法):Serial、ParNew、ParallelScavenge
老年代收集器:CMS(标记-清理)、Serial Old(标记-整理)、Parallel Old(标记整理)
整堆收集器: G1(一个Region中是标记-清除算法,2个Region之间是复制算法) 同时,先解释几个名词:
- 并行(Parallel):多个垃圾收集线程并行工作,此时用户线程处于等待状态
- 并发(Concurrent):用户线程和垃圾收集线程同时执行
- 吞吐量:运行用户代码时间/(运行用户代码时间+垃圾回收时间)
1.Serial收集器
Serial收集器是Java虚拟机中的一种垃圾收集器,它主要用于收集年轻代中的垃圾对象。它是一种单线程的垃圾收集器,它会暂停应用程序的执行,然后扫描年轻代中的对象,将不再被引用的对象标记为垃圾对象,并将它们回收。
Serial收集器的优点是简单,适用于单核处理器和小内存环境下的应用程序。但是,由于它是单线程的,所以它的垃圾收集效率较低,会导致应用程序的停顿时间较长。
在Java虚拟机中,可以通过设置参数来选择使用Serial收集器。例如,可以使用以下命令行参数来启用Serial收集器:
-XX:+UseSerialGC
此外,还可以通过设置以下参数来调整Serial收集器的行为:
-XX:NewRatio:设置年轻代和年老代的比例,默认值为2,表示年轻代占堆内存的1/3。
-XX:SurvivorRatio:设置Eden区和Survivor区的比例,默认值为8,表示Eden区占年轻代内存的8/10,Survivor区占年轻代内存的1/10。
-XX:MaxTenuringThreshold:设置对象进入年老代的年龄阈值,默认值为15,表示对象在年轻代中经过15次Minor GC后,会被移到年老代中。
2.ParNew收集器
ParNew收集器是一种年轻代垃圾收集器,它是Serial收集器的多线程版本。与Serial收集器类似,ParNew收集器也是使用标记-复制算法来回收年轻代中的垃圾对象,但它可以使用多线程来加速垃圾收集的过程。
ParNew收集器的优点是可以利用多核处理器的优势,提高垃圾收集效率,并且可以通过设置参数来控制线程数,以适应不同的硬件环境。此外,它还可以与CMS收集器配合使用,提供更高效的垃圾收集能力。
在Java虚拟机中,可以通过以下命令行参数来启用ParNew收集器:
-XX:+UseParNewGC
此外,还可以通过设置以下参数来调整ParNew收集器的行为:
-XX:ParallelGCThreads:设置垃圾收集的线程数,默认值为CPU核心数。
-XX:MaxTenuringThreshold:设置对象进入年老代的年龄阈值,默认值为15。
-XX:SurvivorRatio:设置Eden区和Survivor区的比例,默认值为8,表示Eden区占年轻代内存的8/10,Survivor区占年轻代内存的1/10。
总之,ParNew收集器是一种高效的年轻代垃圾收集器,可以在多核处理器上发挥优势,提供更快速的垃圾收集能力。
3.Parallel Scavenge 收集器
Parallel Scavenge收集器是一种年轻代垃圾收集器,它是一种多线程的收集器,与ParNew收集器类似,它也是使用标记-复制算法来回收年轻代中的垃圾对象。
Parallel Scavenge收集器的主要特点是注重吞吐量,即在尽可能短的时间内完成垃圾收集,以最大化应用程序的运行时间。它可以通过控制垃圾收集线程的数量和优先级来实现高吞吐量的垃圾收集。
与其他收集器不同,Parallel Scavenge收集器的目标是达到一个可控制的吞吐量,而不是尽可能减少停顿时间。因此,它的停顿时间可能会比其他收集器长一些,但是它可以在更短的时间内完成垃圾收集,从而提高应用程序的吞吐量。
在Java虚拟机中,可以通过以下命令行参数来启用Parallel Scavenge收集器:
-XX:+UseParallelGC
此外,还可以通过设置以下参数来调整Parallel Scavenge收集器的行为:
-XX:ParallelGCThreads:设置垃圾收集的线程数,默认值为CPU核心数。
-XX:MaxGCPauseMillis:设置最大垃圾收集停顿时间,默认值为200毫秒。
-XX:GCTimeRatio:设置垃圾收集时间占总时间的比例,默认值为99,表示垃圾收集时间占总时间的1%。
总之,Parallel Scavenge收集器是一种注重吞吐量的垃圾收集器,可以在多核处理器上发挥优势,提供更高的应用程序吞吐量。
4.Serial Old收集器
在Java虚拟机中,Serial Old收集器是一种传统的、单线程的垃圾收集器,它主要用于收集老年代的垃圾对象。它采用标记-清除算法,首先标记有用的对象,然后清除其他没用的对象,释放内存空间。
Serial Old收集器的优点是简单、高效,适用于小型应用程序和客户端应用程序。但是,它的缺点是无法充分利用多核CPU的优势,因为它是单线程的,不能并行处理垃圾回收任务。此外,它会导致应用程序暂停,因为在垃圾回收期间,应用程序必须等待垃圾回收完成,才能继续执行。
在Java 8之前,Serial Old收集器是默认的老年代收集器。但是,随着Java虚拟机的不断发展,现在更多的应用程序使用并发收集器或G1收集器来管理垃圾对象。
5.Parallel Old收集器
Parallel Old收集器是Java虚拟机中的一种并行垃圾收集器,它主要用于收集老年代的垃圾对象。与Serial Old收集器不同,Parallel Old收集器可以利用多核CPU的优势,使用多线程并行处理垃圾回收任务,从而提高垃圾回收的效率。
Parallel Old收集器采用标记-整理算法,首先标记需要回收的对象,然后将存活的对象移动到一端,然后清理另一端的对象,释放内存空间。由于采用了并行处理,Parallel Old收集器可以在短时间内完成垃圾回收任务,减少应用程序暂停的时间。
Parallel Old收集器适用于大型应用程序和服务器应用程序,可以在多核CPU上充分利用并行处理的优势。但是,它的缺点是在垃圾回收期间,会占用大量的CPU资源,可能会影响应用程序的性能。此外,它也可能会导致应用程序暂停,因为在垃圾回收期间,应用程序必须等待垃圾回收完成,才能继续执行。
6.CMS收集器
CMS收集器是Java虚拟机中的一种并发垃圾收集器,它主要用于收集老年代的垃圾对象。与Parallel Old收集器不同,CMS收集器可以在应用程序运行的同时进行垃圾回收,减少应用程序暂停的时间。
CMS收集器采用标记-清除算法,首先标记需要回收的对象,然后清除这些对象,释放内存空间。由于采用了并发处理,CMS收集器可以在应用程序运行的同时进行垃圾回收,减少应用程序暂停的时间。
CMS收集器适用于大型应用程序和服务器应用程序,可以在应用程序运行的同时进行垃圾回收,减少应用程序暂停的时间。但是,它的缺点是在垃圾回收期间,会占用一定的CPU资源,可能会影响应用程序的性能。此外,由于采用了标记-清除算法,CMS收集器可能会导致内存碎片问题,需要进行额外的处理来解决。
8.G1收集器
G1收集器是Java虚拟机中的一种并发垃圾收集器,它主要用于收集堆内存中的垃圾对象。与CMS收集器不同,G1收集器可以在应用程序运行的同时进行垃圾回收,减少应用程序暂停的时间。
G1收集器采用分代收集的思想,将堆内存分为多个小块,每个小块称为一个区域。它采用标记-整理算法,在每个区域内进行垃圾回收,然后将存活的对象复制到另一个区域。由于采用了并发处理和分代收集的思想,G1收集器可以在应用程序运行的同时进行垃圾回收,减少应用程序暂停的时间。
G1收集器适用于大型应用程序和服务器应用程序,可以在应用程序运行的同时进行垃圾回收,减少应用程序暂停的时间。它还可以根据应用程序的需求动态调整垃圾回收的时间和区域大小,以达到最优的性能。但是,它的缺点是在垃圾回收期间,会占用一定的CPU资源,可能会影响应用程序的性能。此外,由于采用了标记-整理算法,G1收集器不会产生内存碎片问题。
关于gc的选择
除非应用程序有非常严格的暂停时间要求,否则请先运行应用程序并允许VM选择收集器(如果没有特别 要求。使用JVM提供给的默认gc就好)。 如有必要,调整堆大小以提高性能。 如果性能仍然不能满足目标,请使用以下准则作为选择收集器的起点:
- 如果应用程序的数据集较小(最大约100 MB),则选择带有选项-XX:+ UseSerialgc的串行收集器。
- 如果应用程序将在单个处理器上运行,并且没有暂停时间要求,则选择带有选项-XX:+UseSerialgc的串行收集器。
- 如果(a)峰值应用程序性能是第一要务,并且(b)没有暂停时间要求或可接受一秒或更长时间的暂停,则让VM选择收集器或使用-XX:+ UseParallelgc选择并行收集器
- 如果响应时间比整体吞吐量更重要,并且垃圾收集暂停时间必须保持在大约一秒钟以内,则选择具有-XX:+ UseG1gc。(值得注意的是JDK9中CMS已经被Deprecated,不可使用!移除该选项)
- 如果使用的是jdk8,并且堆内存达到了16G,那么推荐使用G1收集器,来控制每次垃圾收集的时间。
- 如果响应时间是高优先级,或使用的堆非常大,请使用-XX:UseZgc选择完全并发的收集器。(值得注意的是JDK11开始可以启动Zgc,但是此时Zgc具有实验性质,在JDK15中[202009发布]才取消实验性质的标签,可以直接显示启用,但是JDK15默认gc仍然是G1)
- 这些准则仅提供选择收集器的起点,因为性能取决于堆的大小,应用程序维护的实时数据量以及可用处 理器的数量和速度。
- 如果推荐的收集器没有达到所需的性能,则首先尝试调整堆和新生代大小以达到所需的目标。
- 如果性能 仍然不足,尝试使用其他收集器
总体原则:减少STOP THE WORD时间,使用并发收集器(比如CMS+ParNew,G1)来减少暂停时间, 加快响应时间,并使用并行收集器来增加多处理器硬件上的总体吞吐量。