鼓励JVM加入GC而不是增加堆?
(注意,当我说“JVM”时,我的意思是“Hotspot”,我正在运行最新的Java 1.6更新。)
示例情况:
我的JVM在-Xmx设置为1gb的情况下运行。 目前,堆已经分配了500mb,其中使用了450mb。 该程序需要在堆上加载另外200 MB。 目前,堆中有300mb的“可收集”垃圾(我们假设它们都是最老的一代)。
在正常操作下,JVM会将堆增长到700 MB左右,并在它到达时进行垃圾收集。
在这种情况下我想要的是JVM首先gc,然后分配新的东西,这样我们最终得到的堆大小保持在500mb,而使用的堆在350mb。
是否有JVM参数组合可以做到这一点?
您可以尝试指定-XX:MinHeapFreeRatio
和-XX:MaxHeapFreeRatio
来控制堆扩展和收缩:
-
-XX:MinHeapFreeRatio
– 当一代中的可用空间百分比低于此值时,生成将扩展为满足此百分比。 默认值为40。 -
-XX:MaxHeapFreeRatio
– 当一代中的可用空间百分比超过此值时,生成将缩小以满足此值。 默认值为70。
您可能还想通过指定-XX:+UseConcMarkSweepGC
来实验并发GC -XX:+UseConcMarkSweepGC
。 根据您的应用程序,它可以使堆大小更低,但需要额外的CPU周期。
否则,JVM将使用您指定的内存作为最佳可用内存。 你可以指定一个较低的数量,如-Xmx768m
来保持它包含它可能运行正常,但你会增加在重负载情况下内存不足的风险。 真的是整体使用更少内存的唯一方法是编写使用更少内存的代码:)
HotSpot中有四个(实际上是五个)不同的垃圾收集器,每个垃圾收集器的选项都不同。
- 串行收集器具有
-XX:MinHeapFreeRatio
和-XX:MaxHeapFreeRatio
,它可以让您或多或少地直接控制行为。 但是我对串行收集器没有多少经验。 - 并行收集器(
-XX:+UseParallelOldGC
)具有-XX:MaxGCPauseMillis=
和-XX:GCTimeRatio=
。 设置较低的最大暂停时间通常会导致收集器使堆更小。 但是,如果暂停时间已经很小,则堆不会变小。 OTOH,如果最大暂停时间设置得太低,应用程序可能会花费所有时间来收集。 设置较低的gc时间比通常也会使堆更小。 您告诉gc您愿意将更多的CPU时间用于收集以换取较小的堆。 但是,这只是一个提示,可能没有任何效果。 在我看来,并行收集器几乎不可用,以最小化堆的大小。 如果你让它运行一段时间并且应用程序的行为保持不变,那么这个收集器工作得更好(它会调整自己)。 - CMS收集器(
-XX:+UseConcMarkSweepGC
)通常需要更大的堆来实现其低暂停时间的主要目标,因此我不会讨论它。 - 新的G1收集器(
-XX:+UseG1GC
)并不像老collections家那样脑死亡。 我发现它自己选择较小的堆大小。 它有很多调整选项,虽然我只是开始研究它们。-XX:InitiatingHeapOccupancyPercent
,-XX:G1HeapWastePercent
,-XX:G1ReservePercent
和-XX:G1MaxNewSizePercent
可能很有用。
看一下垃圾收集器的官方文档以及这个标志列表 。
您可以在分配额外的200MB对象之前调用System.gc()
方法,但这只是对JVM的一个提示,它可以或不可以遵循,并且在任何情况下您都不知道何时发生这种情况。如文档中所述,这是一个尽力而为的请求。
顺便说一下,考虑到垃圾收集是一个繁重的操作,所以如果没有特别需要这样做,只是不要试图强制它。
只是要知道:如果你设置-Xmx1G
然后你告诉JVM 1GB是堆的最大空间,并且因为你指定了它,我不明白为什么它应该尝试保持低,如果它知道1GB仍然可以(我们在内存管理语言的上下文中)。 如果您不希望堆增加那么多只是减少最大值,以便在分配新对象之前强制它执行GC,否则为什么要告诉它使用1GB?