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

时间:2015-05-26 12:10:22

标签: java memory-management garbage-collection

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

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

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

完成的

5 个答案:

答案 0 :(得分:44)

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

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

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

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

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

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

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

还有JEP 346,包含在OpenJDK 12中,它引入了带有{{1}}选项的G1GC的快速内存释放,同样是以一些额外的CPU为代价。它还提到了ShenandoahOpenJ9 VM中的类似功能。

答案 1 :(得分:8)

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

另见related bug report

答案 2 :(得分:3)

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

答案 3 :(得分:3)

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

每当您甚至提到手动调用垃圾收集器的想法时,有些人就会foam之以鼻-但如果要可靠的堆压缩,则需要这样做。

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

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

每天在大型应用程序(一个完整的基于Java的来宾OS)上使用这些选项几个月,并带有动态加载和卸载类-Java进程几乎总是保持在400到800 MB之间。

编辑:“当应用程序空闲时”,JDK 12将具有G1收集器return memory to the OS(不调用System.gc)。后者似乎是为服务器应用程序定义的,但是也许它也适用于台式机和/或它们将使它可定制。

答案 4 :(得分:0)

ZGC以13种Java版本发布,它可以将未使用的堆内存返回给操作系统 请参阅the link