鼓励 JVM 使用 GC 而不是增加堆?

(请注意,当我说“JVM”时,我实际上是指“热点”,并且我正在运行最新的Java 1.6更新。

示例情况:

我的 JVM 在 -Xmx 设置为 1gb 的情况下运行。目前,堆已分配 500mb,其中 450mb 已使用。该程序需要在堆上再加载 200 mb。目前,堆中有300mb的“可收集”垃圾(我们假设它们都是最老的一代)。

在正常操作下,JVM 会将堆增长到 700 mb 左右,并在到达堆时进行垃圾回收。

在这种情况下,我希望JVM首先gc,然后分配新的东西,这样我们最终堆大小保持在500mb,用过的堆保持在350mb。

是否有 JVM 参数组合可以做到这一点?


答案 1

您可以尝试指定 和控制堆扩展和收缩:-XX:MinHeapFreeRatio-XX:MaxHeapFreeRatio

  • -XX:MinHeapFreeRatio- 当一代人中的可用空间百分比低于此值时,该代人将被扩展以满足此百分比。默认值为 40。
  • -XX:MaxHeapFreeRatio- 当一代中的可用空间百分比超过此值时,该代将缩小以满足此值。默认值为 70。

您可能还希望通过指定 来试验并发 GC。根据您的应用程序,它可以以额外的CPU周期为代价来降低堆大小。-XX:+UseConcMarkSweepGC

否则,JVM 将使用您指定的可用内存,当它最优时。您可以指定较低的数量,例如保持它包含,它可能会正常运行,尽管在重负载情况下会增加内存不足的风险。实际上,总体上使用较少内存的唯一方法是编写使用较少内存:)-Xmx768m


答案 2

更新Java 15 又增加了两个收集器。中的一些相关选项包括:ZGC

  • -XX:+UseZGC启用 ZGC
  • -XX:+ZProactive和两者在默认情况下都处于启用状态。ZGC 将主动尝试释放垃圾对象并将释放的内存释放到操作系统。其余选项调整其完成程度。-XX:+ZUncommit
  • -XX:ZCollectionInterval=secondsGC 运行的频率。设置为几秒钟,以确保尽快清理垃圾。(默认情况下为0,即不能保证GC将运行。
  • -XX:ZUncommitDelay=seconds设置堆内存在未提交之前必须未使用的时间量(以秒为单位)。默认情况下,此选项设置为 300(5 分钟)。设置较低的值以更快地取回内存
  • -XX:SoftMaxHeapSize每当应用程序使用的内存超过此限制时,GC 将更频繁地触发。(这可能是OP正在寻找的答案。
  • -XX:SoftRefLRUPolicyMSPerMB不确定此选项的相关频率,但它控制某些缓存对象在内存中保留的时间。

原始答案HotSpot中有四个(实际上是五个)不同的垃圾回收器,每个垃圾回收器的选项都不同。

  • 串行收集器具有 和 ,这使您可以或多或少地直接控制行为。但是,我对串行收集器没有太多经验。-XX:MinHeapFreeRatio-XX:MaxHeapFreeRatio
  • 并行收集器 () 具有 和 。设置较低的最大暂停时间通常会导致收集器使堆变小。但是,如果暂停时间已经很小,则堆不会变小。OTOH,如果最大暂停时间设置得太低,应用程序可能会花费所有时间进行收集。设置较低的 gc 时间比率通常也会使堆变小。您告诉 gc,您愿意将更多的 CPU 时间用于收集,以换取更小的堆。但是,这只是一个提示,可能没有效果。在我看来,并行收集器几乎无法实现,以便最小化堆的大小。如果您让此收集器运行一段时间并且应用程序的行为保持不变,则其工作效果更好(它会自行调整)。-XX:+UseParallelOldGC-XX:MaxGCPauseMillis=<millis>-XX:GCTimeRatio=<N>
  • CMS 收集器 () 通常需要更大的堆来实现其低暂停时间的主要目标,因此我不会讨论它。-XX:+UseConcMarkSweepGC
  • 新的G1收藏家()并不像旧的收藏家那样脑死亡。我发现它自己选择了较小的堆大小。它有很多调整选项,尽管我才刚刚开始研究它们。、和 可能感兴趣。-XX:+UseG1GC-XX:InitiatingHeapOccupancyPercent-XX:G1HeapWastePercent-XX:G1ReservePercent-XX:G1MaxNewSizePercent

看看java标志的列表


推荐