影响垃圾回收性能表现的因素
影响垃圾收集性能的两个最重要因素是总的可用内存和专用于年轻代的内存比例。
- 总堆
- 影响分代堆大小的选项
- 堆大小的默认选项值
- 通过最小化Java堆大小来节省动态占用空间
- 年轻代
- 年轻代堆大小选项值
- 幸存者空间大小
总堆
影响垃圾收集性能的最重要的因素是总可用内存。因为垃圾收集发生在分代内存填满时。吞吐量与可用内存成反比。
注意 下面关于堆的增长和收缩,堆的布局和默认值的讨论,将用串行垃圾收集器作为例子。同时,其他的垃圾收集器使用相似的机制,但此处提供的详细信息可能不适用于其他收集器。有关其他收集器的类似信息,请参阅相应的主题。
影响分代堆大小的选项
许多选项会影响分代堆的大小。图4-1说明了堆中提交空间和虚拟空间之间的区别。在虚拟机初始化时,将保留堆的整个空间。可以使用-Xmx选项指定保留空间的大小。如果-Xms参数的值比-Xmx参数的值小,那么并不是所有保留的空间都立刻提交给虚拟机。未提交的空间在此图中标记为“虚拟”。堆的不同部分,即老一代和年轻一代,可以根据需要增长到虚拟空间的极限。
一些参数代表一部分堆与另外一部分堆的比率。例如,参数-XX:NewRatio代表老一代和年轻一代的相对大小。
堆大小的默认选项
默认情况下,虚拟机会在每次垃圾收集增大或者缩小堆,以尝试在每次垃圾收集中活动对象的可用空间比例保持在特定范围。
这个目标范围由被设置为百分比的选项-XX:MinHeapFreeRation和-XX:MaxHeapFreeRation,并且总大小由-Xms和-Xmx限定。
有了这些选项,如果分代的空闲空间百分比低于40%,则该分代扩展大小以维护40%的空闲空间,直到达到分代可以申请的最大空间。相似的,如果空闲空间超过70%,则分代会收缩以便保持70%的空闲空间,不会小于分代设置的最小值。
Java SE中用于并行垃圾收集器的计算现在用于所有垃圾收集器。计算的一部分是对64位平台最大堆大小的上限。参阅并行垃圾收集器默认堆大小。对于客户端Java虚拟机有类似的计算,这导致比服务器Java虚拟机更小的最大堆的大小。
以下是关于服务器应用程序堆大小的一般准则:
- 除非对暂停时间有要求,否则对虚拟机分配尽可能多的内存。默认的堆大小通常来讲太小。
- 将-Xms和-Xmx设置为相同的值可以通过从虚拟机中删除最重要的大小调整策略来提高可预测性。但是如果选择不当,虚拟机将无法进行补偿。
- 通常随着处理区数量的增加而增加内存,因为可以并行对内存分配。
通过最小化Java堆大小来节省动态占用空间
如果需要最小化应用程序的动态内存占用(在执行过程中消耗最大RAM),那么可以通过最小化Java堆大小来实现这一点。Java SE嵌入式应用程序可能需要这样的配置。
通过命令行降低选项-XX:MaxHeapFreeRatio(默认值是70%)和-XX:MinHeapFreeRation(默认值40%)的值,讲-XX:MaxHeapFreeRatio降低到10%已表明可以成功地减少堆大小,而不会导致太多的性能降低;但是,结果可能因应用程序而异。对这些参数尝试不同的值,直到他们尽可能低,但任然保持可接受的性能。
此外,可以指定-XX:-ShrinkHeapInSteps,这会立刻将Java堆减少到目标大小。使用此设置可能会导致性能下降。默认情况下,Java运行时会以增量方式将Java堆减少到目标大小。此过程需要多个垃圾回收周期
年轻代
在总可用内存之后,影响垃圾收集性能的第二个最重要的因素是专用于年轻代的堆比例。
年轻代越大,minor垃圾收集发生的就越少。然而,对于有限的堆大小,较大的年轻代意味着较小的年老代。这将增加major垃圾收集的频率。最佳选择取决于应用程序分配的对象的生存周期分布。
年轻代堆大小选项值
默认情况下,年轻代的大小由选项-XX:NewRatio控制。
例如,设置-XX:NewRatio=3意味着年轻代和年老代之间的比率是1:3。换句话说eden和survivor空间的总大小将是堆总大小的四分之一。
选项-XX:NewSize和-XX:MaxNewSize从下到上绑定年轻代大小。将这些值设置为相同的值,就像将-Xms和-Xmx设置为相同的值固定总的堆大小一样。这对于只允许整数倍的-XX:NewRatio来说拥有更细的粒度,对年轻代非常有效。
幸存者空间大小
可以使用选项-XX:SurvivorRatio来调整幸存者空间的大小,但通常这对性能并不重要。
例如,-XX:SurvivorRatio=6将幸存者空间和eden的比率设置成1:6。换句话说,每个幸存者空间将是eden的六分之一,因此是年轻代的八分之一(不是七分之一,因为有两个幸存者空间)。
如果幸存者空间太小,则复制垃圾收集将直接溢出到年老代中。如果幸存者空间太大,那么他们是无用的空间。在每次垃圾收集时,虚拟机都会选择一个阈值,即对象在变旧之前可以复制的次数。这个阈值是为了让幸存者保持半满,可以使用日志配置-Xlog:gc,age可以显示这个阈值和新一代对象的ages。他对于观察应用程序的生存期分布也是很有用的。
Option | Default Value |
---|---|
-XX:NewRatio |
2 |
-XX:NewSize |
1310 MB |
-XX:MaxNewSize |
not limited |
-XX:SurvivorRatio |
8 |
从总堆的最大大小和-XX:NewRatio参数值计算年轻代的最大大小。“not limit”默认值意味着计算值不受-XX:MaxNewSize限制,除非再命令上指定了-XX:MaxNewRatio的值。
以下是服务器应用程序的一般准则:
- 首先决定可以给虚拟机提供的最大堆的大小。然后,将性能指标与年轻代大小进行比较,以找到最佳设置。
- 注意最大堆大小总是小于安装在机器上的内存量,以避免过多的分页切花和错误。
- 如果总堆大小是固定的,那么增加年轻代大小需要减少年老代大小。保持年老代足够大,以容纳应用程序在任何给定时间使用的所有活跃数据,外加一些空闲空间(10%到20%或者更多)。
- 受先前年老代约束
- 给年轻代足够的内存
- 随着处理器数量的增加,增加年轻代的大小,因为分配内存可以并行化