首页 > 解决方案 > GC.run 和 GC.run_finalization 有什么区别?

问题描述

有人可以向我解释一下(最好是导致文档)两者之间有什么区别:

jcmd ${jpid} GC.run_finalization
jcmd ${jpid} GC.run

在测试(使用加特林)之后的应用程序(springboot + tomcat)中,很多内存保持分配而不是释放。 在应用程序生命周期中:

我找到的唯一文档是https://docs.oracle.com/javase/8/docs/api/java/lang/System.html#gc--,但它让我更加困惑(我知道 GC.run_finalization 会建议最终确定要释放的对象,而 GC.run 建议准备好内存对象以供将来重用且不必释放)。

提前致谢

标签: javagarbage-collectionjava-12

解决方案


(最好是导致文档)

这里有文档jcmd及其子命令:

该文档解释了jcmd <pid or class> help将列出可用命令,并jcmd <pid or class> help <command>为您提供<command>.


GC.run 和 GC.run_finalization 有什么区别?

从我通过简要查看 JVM 源代码可以看出:

  • GC.run运行完整的垃圾收集。我不知道终结器是否(立即)运行,但我怀疑不是。

  • GC.run_finalization只是打电话System.runFinalization()。根据 javadoc,这会在等待终结的对象上运行终结器;即 GC已经找到的 Java 对象:

    1. 当前无法访问,
    2. 有一个非默认的finalize()方法,和
    3. 尚未被标记为已完成。

(我知道这GC.run_finalization会建议最终确定要释放的对象,而GC.run会建议准备好内存对象以供将来重用并且不必释放)。

它不是那样的。一个正常的 GC 周期是这样的:

  • 垃圾收集找到所有无法访问的对象。
  • 任何需要完成的不可达对象都将添加到队列中。
  • 其他无法访问的对象将立即删除。
  • GC 完成
  • 终结线程唤醒并开始处理其队列中的对象。
    • 每个排队对象的finalize方法都被调用,并被标记为已完成。

最终确定的对象留在原处。如果它们仍然无法访问,它们将在未来的收集中被 GC 删除。

请注意,终结是一种在删除对象之前整理对象的旧机制。绝大多数 Java 对象从未最终确定。


这就是您所看到的行为的解释。

  • 浅锯齿是次要的集合。他们只是在收集伊甸园空间。据推测,“攻击”导致许多对象被永久保存到旧空间。
  • 调用GC_run会触发一个完整的集合,该集合会收集所有空间。这会导致更多的内存被释放。
  • 调用GC_run_finalization没有效果,因为终结不会释放对象。无论如何,队列上可能没有可终结的对象。
  • -

推荐阅读