当垃圾收集器运行并释放内存时,这些内存是返回给操作系统还是作为进程的一部分保留。我的强烈印象是,内存实际上从未释放回操作系统,而是保留为内存区域/池的一部分,以供同一进程重用。
因此,进程的实际内存永远不会减少。 An article这让我想起了这一点,而且 Java 的运行时是用 C/C++ 编写的,所以我想同样的事情也适用?
更新
我的问题是关于 Java 的。我之所以提到 C/C++,是因为我假设 Java 的分配/解除分配是由 JRE 使用某种形式的 malloc/delete 完成的
最佳答案
HotSpot JVM确实将内存释放回操作系统,但不情愿地这样做,因为调整堆的大小很昂贵,并且假设如果您需要该堆,您将再次需要它。
一般来说,收缩能力和行为取决于所选择的垃圾收集器,JVM 版本,因为收缩能力通常是在添加 GC 本身很久之后的更高版本中引入的。一些收集器可能还需要传递其他选项来选择收缩。有些很可能永远不会支持它,例如εGC。 因此,如果需要堆收缩,则应针对特定的 JVM 版本和 GC 配置进行测试。
JDK 8 及更早版本
在这些版本中没有明确的提示内存回收选项,但您可以通过设置 -XX:GCTimeRatio=19 -XX:MinHeapFreeRatio=20 -XX:MaxHeapFreeRatio=30
这将允许它花费更多的 CPU 时间来收集和限制 GC 周期后已分配但未使用的堆内存量。
如果您使用并发收集器,您还可以将 -XX:InitiatingHeapOccupancyPercent=N
与 N 设置为某个较低的值,以让 GC 几乎连续运行并发收集,这将消耗更多 CPU循环但更快地收缩堆。这一般不是一个好主意,但在某些类型的机器上有很多备用 CPU 内核但内存不足时,它是有意义的。
如果您使用的是 G1GC,请注意它只能获得 yield back unused chunks in the middle of the heap 的能力使用 jdk8u20,早期版本只能在堆的末尾返回 block ,这对可以回收的数量施加了很大的限制。
如果您使用具有默认暂停时间目标的收集器(例如 CMS 或 G1),您还可以放宽该目标以减少对收集器的限制,或者您可以切换到并行收集器以优先考虑占用空间而不是暂停时间.
要验证收缩发生或诊断 GC 决定不收缩的原因,您可以使用带有 -XX:+PrintAdaptiveSizePolicy
的 GC 日志记录,也可以提供洞察力,例如当 JVM 尝试为年轻代使用更多内存以满足某些目标时。
JDK 9
添加了 -XX:-ShrinkHeapInSteps
选项,可用于更积极地应用由上一节中提到的选项引起的收缩。 Relevant OpenJDK bug .
用于记录 -XX:+PrintAdaptiveSizePolicy
已替换为 -Xlog:gc+ergo
JDK 12
引入了通过 G1PeriodicGCInterval
( JEP 346 ) 为 G1GC 启用即时内存释放的选项,同样以增加一些 CPU 为代价。 JEP 在 Shenandoah 中也提到了类似的功能。和 OpenJ9 VM .
JDK 13
添加类似行为 for ZGC ,在这种情况下,它默认启用。此外,XXSoftMaxHeapSize
有助于某些工作负载将平均堆大小保持在某个阈值以下,同时仍允许瞬时峰值。
关于java - GC 是否将内存释放回操作系统?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30458195/