garbage-collection - JDK8:老一代对象何时被标记为不可访问?
问题描述
我正在对 Java 服务进行故障排除,在该服务中,它偶尔会将老一代的利用率大幅提高到 80% 以上,然后又回落。
我能够针对主机中的进程运行 jmap。这样做时,无意中触发了进程的完整 GC。然后突然间,老年代的利用率下降到 20%。
这似乎表明老年代空间中有很多无法访问的对象,这些对象只有在完整的 gc 期间才会被清理。
这让我想知道 JVM 何时决定检查老年代对象是否不可访问。这是后台进程吗?还是仅在主要 GC 期间完成?还是通过其他一些机制?我尝试从 Oracle 文档(例如https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html)中获取这些信息,但我没有看到它被描述得太精确。它确实提到了标记是在 GC 期间完成的,但没有说明是否只有这种情况。
如果你们中的一个或多个可以就此主题提供建议或将我指向记录此主题的页面,我将不胜感激。
提前致谢!
更新:
- 使用并行收集器
- 不,我并不是说完整的 GC 是一个错误。相反,我想知道何时将老一代对象标记为可访问/不可访问。我使用的第三方指标之一在其文档中建议它通过旧代空间中的“可访问”对象测量内存利用率,因此我想知道 JVM 何时真正“知道”对象何时不再可访问(例如,仅在完整的GC?)。
解决方案
(它从评论开始,然后增长)
首先,你的老一代增长到 80%,然后在一个完整的 gc 后下降,这并不表示你的应用程序被破坏或你有问题。如果您遇到可归因于 gc 的性能问题并进行测量,请仅开始摆弄 gc!保存之前的 gc 日志并与之后进行比较!
那么你的问题!
不能将对象标记为,unreachable
因为根据定义它是不可访问的。
当老一代是 gc:ed 时,所有活动(可达)对象都是marked
. 然后,根据收集器的不同,扫描(旧代)堆以查找将被压缩的活动对象,或者在 G1 的情况下,活动对象被复制到另一个区域。所有未标记为活动的对象都将根据需要被忽略和覆盖。
根据后台进程,这取决于收集器。并行收集器不会在后台运行,而是会暂停您的应用程序的执行,而例如 CMS 或 G1 将在后台运行(Shenandoah 和 Z 也是如此)。
我错过了你说它是 JDK8 的标题。除非您特别说明,否则默认收集器是上面提到的并行收集器。您的应用程序将在所有可用的 cpu 资源上运行,直到需要进行完整的 gc(本次讨论中唯一有趣的)。然后它将暂停应用程序并使用所有 cpu:s 进行完整的 gc。
如果这不是您想要的,请切换到几乎同时执行 gc 的 CMS。但是请注意,使用 CMS 会为您的应用程序的 CPU 可用性付出代价。由于 CMS 同时运行,它需要 cpu,因此您的应用程序将无法使用该 cpu 来工作。
推荐阅读
- javascript - 如何为 For...in 循环设置限制
- python - 为初学者使用“SCHEDULE”启动 Python 作业
- postgresql - 如何使用 pgAdmin for Postgresql 解决超时问题
- python-3.x - TypeError: add_tab() 接受 1 个位置参数,但给出了 2 个。(OneLineListItem)
- go - 有没有办法在客户端获取 TLS 握手数据?
- python - Leastsq 不适合给定的数据
- python - 使用“Runner”技术将链表的后半部分与前半部分交错
- docker - <
> Airflow2.x 中的模块命名错误 - r - 双 For 循环扫描 2 个整列
- c# - FtpWebRequest.GetResponse() 需要永远