首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >GC会将内存释放回操作系统吗?

GC会将内存释放回操作系统吗?
EN

Stack Overflow用户
提问于 2015-05-26 20:10:22
回答 5查看 27.6K关注 0票数 60

当垃圾收集器运行并释放内存时,这些内存是返回到操作系统,还是作为进程的一部分保留。我有一个强烈的印象,那就是内存实际上永远不会释放回操作系统,而是作为内存区/池的一部分保留下来,供同一进程重用。

因此,进程的实际内存永远不会减少。这让我想起了这一点,An article的运行时是用C/C++编写的,所以我猜同样的事情也适用?

更新

我的问题是关于Java的。我之所以提到C/C++,是因为我假设Java的分配/释放是由JRE使用某种形式的malloc/delete来完成的

EN

回答 5

Stack Overflow用户

发布于 2015-05-27 00:33:23

HotSpot JVM确实将内存释放回操作系统,但这样做是不情愿的,因为调整堆的大小代价很高,而且假定如果您需要该堆一次,那么您将再次需要它。

通常,收缩能力和行为取决于所选的垃圾收集器,JVM版本因为收缩功能通常是在添加GC本身很久之后才引入的。一些收集器可能还需要传递额外的选项才能选择收缩。而有些很可能永远不会支持它,例如EpsilonGC。因此,如果需要堆收缩,应该针对特定的JVM版本和GC配置进行测试。

JDK 8及更早版本

在这些版本中没有显式的内存回收选项,但是您可以通过设置-XX:GCTimeRatio=19 -XX:MinHeapFreeRatio=20 -XX:MaxHeapFreeRatio=30使GC更加积极,这将允许它花费更多的CPU时间来收集,并在GC周期之后限制已分配但未使用的堆内存的数量。

如果您正在使用并发收集器,您还可以将-XX:InitiatingHeapOccupancyPercent=N的N设置为某个较低的值,让GC几乎不间断地运行并发收集器,这将消耗更多的CPU周期,但会更快地缩小堆。这通常不是一个好主意,但在某些具有大量空闲CPU核心但内存不足的机器上,这可能是有意义的。

如果您使用的是G1GC,请注意,它只能通过jdk8u20获得yield back unused chunks in the middle of the heap的能力,早期版本只能在堆的末尾返回块,这对可以回收的块有很大限制。

如果您正在使用具有默认暂停时间目标的收集器(例如CMS或G1),您还可以放宽该目标以减少对收集器的限制,或者您可以切换到并行收集器,以便优先考虑内存占用而不是暂停时间。

为了验证收缩的发生或诊断GC决定不收缩的原因,可以将GC日志记录与-XX:+PrintAdaptiveSizePolicy一起使用也可以提供洞察力,例如,当JVM试图为年轻一代使用更多内存来实现某些目标时。

JDK 9

添加了-XX:-ShrinkHeapInSteps选项,该选项可用于更积极地应用由上一节提到的选项引起的收缩。Relevant OpenJDK bug

对于日志记录,已用-Xlog:gc+ergo取代了-XX:+PrintAdaptiveSizePolicy

JDK 12

引入了通过G1PeriodicGCInterval (JEP 346)为G1GC启用即时内存释放的选项,这也是以一些额外的CPU为代价的。JEP还提到了ShenandoahOpenJ9 VM中的类似功能。

JDK 13

添加类似的行为for ZGC,在本例中,它是默认启用的。

票数 84
EN

Stack Overflow用户

发布于 2015-05-26 20:59:01

在某些情况下,JVM确实会释放回内存,但(出于性能原因)只要有一些内存被垃圾回收,就不会发生这种情况。这也取决于JVM,操作系统,垃圾收集器等。你可以用JConsole,VisualVM或者其他分析器来观察你的应用的内存消耗。

另请参阅此related bug report

票数 12
EN

Stack Overflow用户

发布于 2018-11-13 23:52:36

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

从Java12开始,如果应用程序空闲,G1就会自动执行此操作。

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

代码语言:javascript
复制
-XX:+UseG1GC -XX:MaxHeapFreeRatio=30 -XX:MinHeapFreeRatio=10

几个月来,我每天在一个大型应用程序(整个基于Java的来宾操作系统)中使用这些选项,这些应用程序动态地加载和卸载类-Java进程几乎总是在400到800 MB之间。

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30458195

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档