垃圾收集器不会自行释放内存

问题描述 投票:0回答:2

为什么我的垃圾收集器(G1 GC)尽管可以释放内存却不释放内存? Used Heap随着时间的推移在上升,最后一步下降是因为我通过

jcmd <pid> GC.run

强制GC释放内存

为什么?这是正常行为吗?

我用这些参数启动了 GC

-Xms64m -Xmx256m -XX:G1ReservePercent=50

java garbage-collection visualvm g1gc
2个回答
4
投票

该图看起来像正常行为。

G1 GC 是分代收集器。这意味着堆分为(在这种情况下)2 代:新旧。新一代比旧一代收集得更频繁。在许多新一代集合中存活下来的对象被“提升”到老年代。新生代相对较小,并且经常被 GC。老一代更大,但只有在它开始变满时才会进行 GC。

所以...该图显示了一系列与新一代系列相对应的“精细”锯齿。随着幸存者对象被提升到老年代,这条线呈上升趋势。并且老年代收集没有运行......因为 JVM 还没有认为老年代已经足够满以保证收集。

然后,你打电话给

jcmd <pid> GC.run
。这触发了老年代收集,你收回了大约 10MB 的内存。 (你不需要那样做。尽早释放内存除了改变图形之外什么都不做。)

然后恢复新的收集模式


问:这正常吗?

A:是的。

问:这里有问题吗?

A:没有证据表明有问题。当然不是 GC 本身。您的应用程序可能存在内存泄漏,但没有任何明确的证据。

问:如果你没有打电话

jcmd <pid> GC.run
怎么办?

A:在某个时候,JVM 会决定老年代已经足够满,可以启动老年代收集。没有必要强迫它。事实上,强制执行通常是一个坏主意

Q:这是GC的缺陷吗?为什么 GC 在 >I< think it is free?

时不释放内存

A:不,这不是缺陷。这是设计

尽早回收内存的(假设的)好处与运行垃圾收集器的成本之间存在权衡。作为一般规则,当可收集垃圾与不可收集对象的比率很高时,GC 算法是最有效的;即当堆接近(但不是接近)满时。

请注意,图表未显示 可回收 空间。 JVM 可以有效地确定有多少空间是可回收的唯一方法是通过实际运行 GC 来回收它。 JVM 持续运行 GC 只是为了在 >you< think it should be.

时释放内存是低效的(而且毫无意义)

最后,即使您确实强制运行 GC,JVM 也不愿意将内存还给操作系统 供其他进程使用。挂在内存上比不断缩小然后重新扩大堆的大小更有效。


-2
投票

这很常见,也是垃圾收集的缺陷之一。 您可以告诉垃圾收集器他应该开始清理您的内存,但这并不意味着他会这样做。

System.gc();

Oracle 官方文档指出:

调用 gc 方法表明 Java 虚拟机努力回收未使用的对象,以使它们当前占用的内存可用于快速重用

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