并行收集器(这里也称为吞吐量收集器是类似于串行收集器的分代收集器。串行收集器和并行收集器之间的主要区别在于并行收集器具有多个线程,用于加速垃圾收集。并行收集器通过命令行选项启用-XX:+UseParallelGC。默认情况下,使用此选项,次要和主要收集并行运行以进一步减少垃圾收集开销。

并行收集器的垃圾收集器线程数

在具有硬件线程且大于 8 的机器上,并行收集器使用的固定分数作为垃圾收集器线程的数量。

对于较大的值,该分数约为 5/8 。当值低于 8 时,使用的数字是。在选定的平台上,这一比例下降到 5/16。垃圾收集器线程的具体数量可以通过命令行选项(稍后介绍)进行调整。在具有一个处理器的主机上,由于并行执行(例如同步)所需的开销,并行收集器的性能可能不如串行收集器。但是,在运行具有中型到大型堆的应用程序时,它通常在具有两个处理器的计算机上略胜于串行收集器,并且当有两个以上的处理器可用时,其性能通常明显优于串行收集器。

可以使用命令行选项控制垃圾收集器线程的数量-XX:ParallelGCThreads=. 如果您使用命令行选项调整堆,那么并行收集器获得良好性能所需的堆大小与串行收集器所需的堆大小相同。但是,启用并行收集器应该会使收集暂停更短。由于多个垃圾收集器线程参与次要收集,因此在收集过程中由于从年轻代到老年代的提升,可能会产生一些碎片。参与次要收集的每个垃圾收集线程都会保留一部分老年代用于提升,将可用空间划分为这些“提升缓冲区”会导致碎片效应。减少垃圾收集器线程的数量并增加老年代的大小将减少这种碎片效应。

并行收集器中的世代排列

在并行收集器中,世代的排列是不同的。
并行收集器 - 图1
图 6-1 并行收集器中的世代排列

并行收集器人体工程学

当使用 选择并行收集器时-XX:+UseParallelGC,它启用了一种自动调整方法,允许您指定行为而不是生成大小和其他低级调整细节。

用于指定并行收集器行为的选项

您可以指定最大垃圾回收暂停时间、吞吐量和占用空间(堆大小)。

  • 最大垃圾回收暂停时间:最大暂停时间目标由命令行选项-XX:MaxGCPauseMillis= 指定。这被解释为暗示需要毫秒或更短的暂停时间;默认情况下,没有最大暂停时间目标。如果指定了暂停时间目标,则会调整堆大小和其他与垃圾收集相关的参数,以尝试使垃圾收集暂停时间短于指定值;然而,所需的停顿时间目标可能并不总能达到。这些调整可能会导致垃圾收集器降低应用程序的整体吞吐量。

  • 吞吐量:吞吐量目标是根据垃圾收集所花费的时间与垃圾收集之外所花费的时间(称为应用程序时间)来衡量的。目标由命令行选项-XX:GCTimeRatio= 指定,它将垃圾收集时间与应用程序时间的比率设置为1 / (1 + )。例如,-XX:GCTimeRatio=19 将垃圾收集总时间的 1/20 或 5% 设定为目标。默认值为 99,因此垃圾回收时间的目标为 1%。

  • 占用空间:使用选项-Xmx指定最大堆占用空间。此外,只要满足其他目标,收集器就有一个隐含的目标,即最小化堆的大小。

并行收集器目标的优先级

目标是最大暂停时间目标、吞吐量目标和最小占用空间目标,目标按以下顺序处理:首先达到最大暂停时间目标。只有在满足之后才能解决吞吐量目标。同样,只有在实现前两个目标之后,才会考虑足迹目标。

并行收集器生成大小调整

收集器保存的平均暂停时间等统计信息在每次收集结束时更新。然后进行测试以确定是否已实现目标,并对代的规模进行任何必要的调整。例外是显式垃圾收集,例如,调用System.gc()在保持统计信息和调整世代大小方面被忽略。

增加和缩小代的大小是通过按代大小固定百分比的增量来完成的,以便代向上或向下逐步达到其所需的大小。增长和收缩以不同的速度完成。默认情况下,代以 20% 的增量增长并以 5% 的增量收缩。增长的百分比由年轻代的命令行选项-XX:YoungGenerationSizeIncrement=和年老代的-XX:TenuredGenerationSizeIncrement= 控制代缩小的百分比由命令行标志-XX:AdaptiveSizeDecrementScaleFactor= 调整。如果增长增量是X %,那么收缩的减量是X / D %。

如果收集器决定在启动时增加代,那么增量中会增加一个补充百分比。此补充会随着收集次数的增加而衰减,不会产生长期影响。补充的目的是提高启动性能。收缩的百分比没有补充。如果没有达到最大暂停时间目标,那么一次只缩小一个代的大小。如果两代的停顿时间都高于目标值,那么停顿时间较大的代规模先缩小。如果未满足吞吐量目标,则增加两代的大小。每个都按其各自对总垃圾收集时间的贡献成比例增加。例如,如果年轻代的垃圾回收时间是总回收时间的 25%,如果年轻代的完整增量为 20%,那么年轻代将增加 5%。

并行收集器默认堆大小

除非在命令行中指定了初始和最大堆大小,否则它们是根据机器上的内存量计算的。默认的最大堆大小是物理内存的四分之一,而初始堆大小是物理内存的 1/64分配给年轻代的最大空间量是总堆大小的三分之一

并行收集器初始和最大堆大小的规范

您可以使用选项-Xms(初始堆大小)和-Xmx(最大堆大小)指定初始和最大堆大小。如果您知道您的应用程序需要多少堆才能正常工作,那么您可以将-Xms和设置-Xmx为相同的值。如果您不知道,那么 JVM 将首先使用初始堆大小,然后增加 Java 堆,直到找到堆使用和性能之间的平衡。其他参数和选项可能会影响这些默认值。要验证您的默认值,请使用 -XX:+PrintFlagsFinal选项并在输出中查找-XX:MaxHeapSize。例如,在 Linux 或 Solaris 上,您可以运行以下命令:

java -XX:+PrintFlagsFinal -version | grep 最大堆大小

过长的并行收集器时间和 OutOfMemoryError(即什么时候抛出OOM)

如果在垃圾收集 (GC) 上花费了太多时间,并行收集器会抛出一个错误OutOfMemoryError。
如果超过 98% 的总时间花在垃圾收集上,而回收的堆不到 2% ,则抛出OutOfMemoryError。此功能旨在防止应用程序长时间运行而由于堆太小而进展甚微或没有进展。如有必要,可以通过将选项添加-XX:-UseGCOverheadLimit到命令行来禁用此功能。

并行收集器测量

并行收集器的详细垃圾收集器输出与串行收集器的输出基本相同。