GC是否将内存释放回操作系统?

问题描述 投票:29回答:4

当垃圾收集器运行并释放内存时,此内存会返回到操作系统,或者它是否作为进程的一部分保留。我的印象是,内存从未实际发布回操作系统,而是作为内存区/池的一部分保留,以便由同一进程重用。

结果,进程的实际内存永远不会减少。 An article提醒我的是这个,Java的Runtime是用C / C ++编写的,所以我想同样的事情也适用?

更新 我的问题是关于Java。我提到C / C ++,因为我假设Java的分配/解除分配是由JRE使用某种形式的malloc / delete完成的

java memory-management garbage-collection
4个回答
46
投票

HotSpot JVM确实将内存释放回操作系统,但是不情愿地这样做,因为调整堆的大小是昂贵的,并且假设如果你需要那个堆,一旦你再次需要它。

您可以通过设置-XX:GCTimeRatio=19 -XX:MinHeapFreeRatio=20 -XX:MaxHeapFreeRatio=30使其更具攻击性,这将允许它在GC周期后花费更多的CPU时间来收集和约束已分配但未使用的堆内存量。

假设您正在使用并发收集器,您还可以将带有N的-XX:InitiatingHeapOccupancyPercent=N设置为某个较低的值,以使GC几乎连续地运行并发集合,这将消耗更多的CPU周期,但会更快地缩小堆。这通常不是一个好主意,但在某些类型的具有大量备用CPU内核但内存不足的机器上它是有意义的。

如果您正在使用具有默认暂停时间目标(CMS或G1)的收集器,您还可以放宽该目标以减少对收集器的约束,或者您可以切换并行收集器以在暂停时间内确定占用空间的优先级。

此外,使用Java 9,-XX:-ShrinkHeapInSteps选项可用于更积极地应用前两个选项引起的收缩。 Relevant OpenJDK bug

请注意,缩小的能力和行为取决于所选的垃圾收集器。例如,G1只获得了使用jdk8u20的yield back unused chunks in the middle of the heap的能力,而ZGC确实not yet支持它,而epsilon收集器很可能永远不会。 因此,如果需要堆缩小,则应针对特定的JVM版本和GC配置进行测试。

使用PrintAdaptiveSizePolicy进行GC记录也可以提供洞察力,例如:当JVM试图为年轻一代使用更多内存来实现某些目标时。

OpenJDK 12中还包含JEP 346,它使用G1PeriodicGCInterval选项为G1GC引入了快速内存释放,同样以牺牲一些额外的CPU为代价。它还提到了ShenandoahOpenJ9 VM中的类似特征。


9
投票

在某些情况下,JVM确实释放了内存,但是(出于性能原因)只要某些内存被垃圾收集,就不会发生这种情况。它还取决于JVM,操作系统,垃圾收集器等。您可以使用JConsole,VisualVM或其他分析器来监视应用程序的内存消耗。

另见related bug report


3
投票

本文here解释了GC如何在Java 7中工作。简而言之,有许多不同的垃圾收集器可用。通常,内存是为Java进程保留的,只有一些GC将它释放到系统中(根据我的要求,我认为)。但是,Java进程使用的内存不会无限增长,因为Xmx选项定义了一个上限(通常为256m,但我认为它取决于OS /机器)。


3
投票

如果您使用G1收集器并偶尔调用System.gc()(我每分钟执行一次),Java将可靠地收缩堆并将内存返回给操作系统。

每当你提到手动调用垃圾收集器的想法时,有些人会在嘴里冒泡 - 但如果你想要可靠的堆压缩,你需要这样做。

我建议将这些选项与上述建议结合使用,以获得非常紧凑的驻留进程大小:

-XX:+UseG1GC -XX:MaxHeapFreeRatio=30 -XX:MinHeapFreeRatio=10

几个月来一直使用这些选项与一个大型应用程序(一个完整的基于Java的客户操作系统),动态加载和卸载类 - 而Java过程几乎总是保持在400到800 MB之间。

编辑:当应用程序空闲时,JDK 12将具有G1收集器return memory to the OS(不调用System.gc)。后一个术语似乎是为服务器应用程序定义的,但它也可能适用于桌面和/或它们可以自定义。

© www.soinside.com 2019 - 2024. All rights reserved.