初始堆大小和最大堆大小

了解垃圾收集器 (GC) 的操作有助于设置初始堆大小和最大堆大小,以实现对堆的高效管理。

垃圾收集器会因以下原因调整堆大小以将占用率保持在 40% 到 70% 之间:
  • 堆占用率大于 70% 会导致更频繁的 GC 周期,致使性能降低。 您可以通过设置 -Xminf 选项来改变此行为。
  • 堆占用率小于 40% 意味着不频繁的 GC 周期。 但是,这些周期会超过必需时间而导致更长的暂停时间,致使性能降低。 您可以通过设置 -Xmaxf 选项来改变此行为。
如果您未设置初始或最大堆大小,那么 GC 会根据需要扩展和缩小堆。 但是,如果使用 -Xms-Xmx 选项来修正堆大小,那么 GC 不会扩展或缩小 Java™ 堆。 要优化应用程序性能并保持在 40 - 70% 范围内,那么最大堆大小设置应因此至少比应用程序的最大占用率高出 43%。 例如,如果应用程序的最大占用率为 70 MB,那么应按照以下计算所示设置 100 MB 的最大堆大小:
70 + (70 * 43/100)

将最小和最大堆大小设置为相同值通常不是很好的做法,因为垃圾回收会延迟到堆充满后才开始。 因此,在 GC 第一次运行时,该过程可能花费更长时间。 此外,堆很有可能被分段,并且需要堆压缩。 以应用程序所需的最小堆大小启动应用程序。 当 GC 启动时,由于堆较小,因此 GC 将频繁且高效地运行。

如果 GC 无法找到足够的垃圾,那么将运行压缩。 如果 GC 找到了足够的垃圾,或者满足堆扩展的任何其他条件 (请参阅 OpenJ9 用户文档中的 堆分配 ) ,那么 GC 将扩展堆。

因此,应用程序通常会运行到堆满为止。 然后,连续的垃圾回收周期将使垃圾恢复。 在堆装满活动对象时,GC 将压缩堆。 如果仍未恢复足够的垃圾,那么 GC 将扩展堆。

从先前的描述中,您可以看到,随着应用程序需求的增加,GC 将压缩堆,因此,在堆扩展时,它将使用原始堆底部的压缩对象来进行扩展。 由于在发现需要压缩时才以可能的最小堆大小运行压缩,因此该过程是一种高效的管理堆的方式。 随着堆的增加,将以最小的堆大小来执行压缩。 一些迹象表明,应用程序的对象初始集趋向于键或根集,因此较早地压缩它们能够为短生命周期对象释放剩余的堆。

最终,JVM 将拥有最大大小的堆,所有长生命周期对象压缩在堆的底部。 当压缩处于成本最低的阶段时,将发生压缩。 与收集和压缩非常大的分段堆所用成本相比,扩展堆所需的处理和内存使用量微乎其微。