影响垃圾收集性能的因素

影响垃圾收集性能的两个最重要的因素是总可用内存和专用于年轻代的堆的比例。

总堆

影响垃圾收集性能的最重要因素是总可用内存。

由于集合在代数填满时发生,因此吞吐量与可用内存量成反比。

注意

以下有关堆的增长和收缩,堆布局和默认值的讨论使用串行收集器作为示例。

虽然其他收藏家使用类似的机制,但此处提供的详细信息可能不适用于其他收藏家。

有关其他收集器的类似信息,请参阅相应主题。

堆影响选项会影响生成大小

许多选项会影响生成大小。

图4-1说明了堆中的已提交空间和虚拟空间之间的区别。

在初始化虚拟机时,将保留堆的整个空间。

可以使用-Xmx选项指定保留空间的大小。

如果-Xms参数的值小于-Xmx参数的值,则不会将所有保留的空间立即提交给虚拟机。

未提交的空间在此图中标记为“虚拟”。

堆的不同部分,即旧一代和年轻一代,可以根据需要增长到虚拟空间的极限。

一些参数是堆的一部分与另一部分的比率。

例如,参数 -XX:NewRatio 表示老一代与年轻一代的相对大小。

图4-1堆选项

jsgct_dt_006_prm_gn_sz_new.png

堆大小的默认选项值

默认情况下,虚拟机会在每个集合中增大或缩小堆,以尝试将可用空间的比例保持在特定范围内每个集合的活动对象。

通过选项 -XX:MinHeapFreeRatio=<minimum>-XX:MaxHeapFreeRatio=<maximum> 将此目标范围设置为百分比, 并且总大小在 -Xms<min> 以下由 -Xmx<max> 限制在下方。

表4-1中显示了64位Solaris操作系统(SPARC Platform Edition)的缺省选项。

  • 表4-1 64位Solaris操作系统的缺省选项
参数 说明
-XX:MinHeapFreeRatio 40
-XX:MaxHeapFreeRatio 70
-Xms 6656 KB
-Xmx calculated

有了这些选项,如果一代中的可用空间百分比低于40%,那么该代将扩展到维持40%的可用空间,直到该代的最大允许空间。类似地,如果自由空间超过70%,那么该代收缩使得只有70%的空间是免费的,受制于该代的最小尺寸。

如表4-1中所述,默认的最大堆大小是由JVM计算的值。

Java SE中用于并行收集器和服务器JVM的计算现在用于所有垃圾收集器。部分计算是64位平台的最大堆大小的上限。请参见并行收集器默认堆大小。客户端JVM有类似的计算,这导致最大堆大小小于服务器JVM。

  • 以下是有关服务器应用程序的堆大小的一般准则:
  1. 除非您遇到暂停问题,否则请尽量为虚拟机授予尽可能多的内存。默认大小通常太小。

  2. 将-Xms和-Xmx设置为相同的值可通过从虚拟机中删除最重要的大小决策来提高可预测性。但是,如果做出糟糕的选择,则虚拟机无法进行补偿。

  3. 通常,在增加处理器数量时增加内存,因为可以使分配并行。

通过最小化Java堆大小来节省动态占用空间

如果需要最小化应用程序的动态内存占用(执行期间消耗的最大RAM),则可以通过最小化Java堆大小来实现此目的。

Java SE Embedded应用程序可能需要这样做。

通过使用命令行选项-XX:MaxHeapFreeRatio和-XX:MinHeapFreeRatio降低选项-XX:MaxHeapFreeRatio(默认值为70%)和-XX:MinHeapFreeRatio(默认值为40%)的值来最小化Java堆大小。

将-XX:MaxHeapFreeRatio降低到10%并且-XX:MinHeapFreeRatio已经证明可以成功地减小堆大小而不会降低太多性能;但是,根据您的应用,结果可能会有很大差异。尝试使用这些参数的不同值,直到它们尽可能低,但仍保持可接受的性能。

此外,您可以指定-XX:-ShrinkHeapInSteps,它会立即将Java堆减少到目标大小(由参数-XX:MaxHeapFreeRatio指定)。使用此设置可能会降低性能。默认情况下,Java运行时会逐渐将Java堆减少到目标大小;此过程需要多个垃圾回收周期。

年轻代

在总可用内存之后,影响垃圾收集性能的第二个最有影响的因素是专用于年轻代的堆的比例。

年轻一代越大,发生的次要收集就越少。但是,对于有限的堆大小,较大的年轻代意味着较小的老一代,这将增加主要集合的频率。最佳选择取决于应用程序分配的对象的生命周期分布。

年轻代大小选项

默认情况下,年轻代的大小由选项-XX:NewRatio控制。

例如,设置-XX:NewRatio=3意味着年轻一代和老一代之间的比例是1:3。换句话说,伊甸园和幸存者空间的组合大小将是总堆大小的四分之一。

选项-XX:NewSize和-XX:MaxNewSize从下方和上方绑定年轻代大小。将这些设置为相同的值可以修复年轻代,就像将-Xms和-Xmx设置为相同的值来修复总堆大小一样。这对于以比-XX:NewRatio允许的整数倍更精细的粒度调整年轻代有用。

幸存者空间大小

您可以使用选项-XX:SurvivorRatio来调整幸存者空间的大小,但这通常对性能不重要。

例如,-XX:SurvivorRatio = 6将eden和幸存者空间之间的比率设置为1:6。换句话说,每个幸存者空间将是伊甸园大小的六分之一,因此是年轻一代的八分之一(不是七分之一,因为有两个幸存者空间)。

如果幸存者空间太小,那么复制集合会直接溢出到旧一代。如果幸存者空间太大,那么它们就没用了。在每次垃圾收集时,虚拟机会选择一个阈值编号,该阈值编号是对象在旧版之前可以复制的次数。选择此阈值是为了使幸存者保持半满。您可以使用日志配置-Xlog:gc,age可用于显示此阈值和新一代对象的年龄。它对于观察应用程序的生命周期分布也很有用。

表4-2提供了64位Solaris的缺省值。

表4-2 Survivor Space Sizing的默认选项值

参数 默认值
-XX:NewRatio 2
-XX:NewSize 1310 MB
-XX:MaxNewSize not limited
-XX:SurvivorRatio 8

年轻代的最大大小是根据总堆的最大大小和-XX:NewRatio参数的值计算的。

-XX:MaxNewSize参数的“不受限制”默认值表示计算值不受-XX:MaxNewSize限制,除非在命令行上指定了-XX:MaxNewSize的值。

最佳实践

以下是服务器应用程序的一般准则:

首先确定您可以为虚拟机提供的最大堆大小。然后,根据年轻代尺寸绘制性能指标,以找到最佳设置。

请注意,最大堆大小应始终小于计算机上安装的内存量,以避免过多的页面错误和颠簸。

如果总堆大小是固定的,那么增加年轻代的大小需要减少旧的生成大小。保持老一代足够大以容纳应用程序在任何给定时间使用的所有实时数据,加上一些松弛空间(10到20%或更多)。

  • 遵守先前对旧一代的约束:

给年轻一代留下充足的空间。

随着处理器数量的增加,增加年轻代的大小,因为分配可以并行化。

参考资料

https://docs.oracle.com/javase/9/gctuning/factors-affecting-garbage-collection-performance.htm