【问题标题】:Garbage Collector does not release memory on his own垃圾收集器不会自行释放内存
【发布时间】:2021-11-22 01:28:13
【问题描述】:

为什么我的垃圾收集器 (G1 GC) 没有释放内存? Used Heap随着时间的推移而上升,最后的step fall是因为我通过jcmd <pid> GC.run强制GC释放内存

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

我用这些参数-Xms64m -Xmx256m -XX:G1ReservePercent=50启动了GC

【问题讨论】:

  • 您可能想阅读thisthis
  • 这里没有“释放内存”这回事。在整个记录时间内,分配了 82MB 的堆。只有该堆中已用内存的一部分发生了变化——大约为 5MB。

标签: java garbage-collection visualvm g1gc


【解决方案1】:

该图表看起来像正常行为。

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

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

然后,你打电话给jcmd <pid> GC.run。这触发了老年代收集,并且您获得了大约 10MB 的内存。

然后新的收集模式恢复了。


问:这正常吗?

答:是的。

问:这里有问题吗?

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

问:如果你没有打电话给jcmd <pid> GC.run怎么办?

A:在某个时候,JVM 会判断老年代已经满了,足以保证开始老年代收集。没有必要强迫它。事实上,强迫它通常是一个坏主意

问:这是 GC 的缺陷吗?为什么当 >I

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

在提早回收内存的(假定的)好处与运行垃圾收集器的成本之间需要权衡取舍。一般来说,当可回收垃圾与不可回收对象的比例很高时,GC 算法效率最高;即当堆接近(但不是接近)到满时。

请注意,即使您确实强制 GC 运行,JVM 也不愿意将内存返还给操作系统以供其他进程使用。

【讨论】:

  • OP“找回”的空间是 10MB。但实际上,即使在手动 GC 之前,内存也是可回收的,因此可以在应用程序真正需要它的情况下使用。它只是没有在用于绘制此图的统计数据中考虑。所以所有手动触发的GC实现,除了提高CPU利用率,就是改变绘制的图。
【解决方案2】:

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

System.gc();

Oracle 官方文档指出:

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

【讨论】:

  • 这不是缺陷。这是一个经过深思熟虑的 Java SE 设计特性。它是在早期添加的,以便系统管理员/用户有办法保护自己免受过度手动触发 GC 的库代码/应用程序的影响。
猜你喜欢
  • 2019-05-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-02
  • 1970-01-01
相关资源
最近更新 更多