The 热点 JVM确实将内存释放回操作系统,但不情愿地这样做,因为调整堆大小的成本很高,并且假设如果您需要该堆一次,您将再次需要它。
一般来说,收缩能力和行为取决于所选择的垃圾收集器、JVM 版本,因为收缩功能通常是在添加 GC 本身很久之后才在后续版本中引入的。一些收集器可能还需要传递额外的选项才能选择缩小。有些人很可能永远不会支持它,例如EpsilonGC。
因此,如果需要堆收缩,则应针对特定 JVM 版本和 GC 配置进行测试。
JDK 8 及更早版本
在这些版本中没有用于提示内存回收的明确选项,但您可以通过设置来使 GC 更加积极-XX:GCTimeRatio=19 -XX:MinHeapFreeRatio=20 -XX:MaxHeapFreeRatio=30
这将允许它花费更多的 CPU 时间来收集并限制 GC 周期后已分配但未使用的堆内存量。
如果您使用并发收集器,您还可以设置-XX:InitiatingHeapOccupancyPercent=N
将 N 设置为某个较低值,让 GC 几乎连续运行并发收集,这将消耗更多 CPU 周期,但会更快收缩堆。这一般来说这不是一个好主意,但在某些类型的具有大量备用 CPU 核心但内存不足的机器上,它是有意义的。
如果您使用的是 G1GC,请注意它仅获得了以下能力:返回堆中间未使用的块对于 jdk8u20,早期版本只能返回堆末尾的块,这对可回收的量设置了很大的限制。
如果您使用具有默认暂停时间目标的收集器(例如 CMS 或 G1),您还可以放宽该目标以减少对收集器的限制,或者您可以切换到并行收集器以优先考虑占用空间而不是暂停时间。
要验证是否发生收缩或诊断 GC 决定不收缩的原因,您可以使用 GC 日志记录-XX:+PrintAdaptiveSizePolicy
还可以提供见解,例如当 JVM 尝试为年轻代使用更多内存来实现某些目标时。
JDK 9
添加了-XX:-ShrinkHeapInSteps
选项可用于更积极地应用上一节中提到的选项引起的收缩。相关 OpenJDK 错误.
用于记录-XX:+PrintAdaptiveSizePolicy
已替换为-Xlog:gc+ergo
JDK 12
引入了通过以下选项启用 G1GC 快速内存释放的选项G1PeriodicGCInterval
(JEP 346),同样以一些额外的 CPU 为代价。 JEP 中也提到了类似的功能谢南多厄和OpenJ9 虚拟机.
JDK 13
添加类似的行为for ZGC,在这种情况下它是默认启用的。此外XXSoftMaxHeapSize
对于某些工作负载来说,将平均堆大小保持在某个阈值以下,同时仍然允许瞬时峰值可能会有所帮助。