java - GC.run 和 GC.run_finalization 有什么区别?
问题描述
有人可以向我解释一下(最好是导致文档)两者之间有什么区别:
jcmd ${jpid} GC.run_finalization
jcmd ${jpid} GC.run
在测试(使用加特林)之后的应用程序(springboot + tomcat)中,很多内存保持分配而不是释放。 在应用程序生命周期中:
- 攻击开始(加特林模拟),额外的tomcat执行线程启动,攻击结束
- 一段时间后 spring/tomcat 会话对象超时(session.servlet.timeout)
- 我希望释放会话对象并释放额外的 tomcat 执行程序,但它不会发生
- 我等了很长时间(比如说几天)......这就是上图的开始
- 如果我执行 GC.run_finalization - 什么也没有发生(只是更快的“锯掉”)
- 如果我执行 GC.run - 如图所示释放内存
我找到的唯一文档是https://docs.oracle.com/javase/8/docs/api/java/lang/System.html#gc--,但它让我更加困惑(我知道 GC.run_finalization 会建议最终确定要释放的对象,而 GC.run 建议准备好内存对象以供将来重用且不必释放)。
提前致谢
解决方案
(最好是导致文档)
这里有文档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 对象:- 当前无法访问,
- 有一个非默认的
finalize()
方法,和 - 尚未被标记为已完成。
(我知道这
GC.run_finalization
会建议最终确定要释放的对象,而GC.run
会建议准备好内存对象以供将来重用并且不必释放)。
它不是那样的。一个正常的 GC 周期是这样的:
- 垃圾收集找到所有无法访问的对象。
- 任何需要完成的不可达对象都将添加到队列中。
- 其他无法访问的对象将立即删除。
- GC 完成
- 终结线程唤醒并开始处理其队列中的对象。
- 每个排队对象的
finalize
方法都被调用,并被标记为已完成。
- 每个排队对象的
最终确定的对象留在原处。如果它们仍然无法访问,它们将在未来的收集中被 GC 删除。
请注意,终结是一种在删除对象之前整理对象的旧机制。绝大多数 Java 对象从未最终确定。
这就是您所看到的行为的解释。
- 浅锯齿是次要的集合。他们只是在收集伊甸园空间。据推测,“攻击”导致许多对象被永久保存到旧空间。
- 调用
GC_run
会触发一个完整的集合,该集合会收集所有空间。这会导致更多的内存被释放。 - 调用
GC_run_finalization
没有效果,因为终结不会释放对象。无论如何,队列上可能没有可终结的对象。
-
推荐阅读
- amazon-web-services - 是否可以在本地 K8s 集群上拥有 AWS EBS 持久卷?
- git - Git 恢复到对特定文件的多次提交
- c++ - 将应用程序从 gcc4.9.3 迁移到 gcc8.3.0 时出现 std::string 分配器编译错误
- python - 将参数传递给 Python 中的装饰器类
- javascript - Hide a component using selected option in select2
- python - Youtube API returning 1 video per request or errors
- r - 从 ffdf 中的时间戳/日期时间列中分离时间和日期值
- java - Glide OnResource 设置回调类成员变量以便复用
- angular - angular 的 Apollo 客户端:从 graphql 文件生成代码
- html - Vertical overflow always showing scrollbar which never works