Java 7 G1GC 奇怪的行为

Posted

技术标签:

【中文标题】Java 7 G1GC 奇怪的行为【英文标题】:Java 7 G1GC strange behaviour 【发布时间】:2013-04-04 17:36:51 【问题描述】:

最近我尝试在我的 java 处理器中使用 jdk1.7.0-17 中的 G1GC,该处理器正在处理从 MQ 接收到的许多类似消息(大约 15-20 req/sec)。每条消息都在由 Java 有限线程池服务的单独线程(大约 100 个处于稳定状态的线程)中处理。令人惊讶的是,我检测到了奇怪的行为 - 一旦 GC 开始完整的 gc 循环,它就开始使用大量的处理时间(高达 100% 的 CPU 甚至更多)。我多次重构代码,目标是优化它并使其更轻量级。但没有任何显着的结果 - 行为是相同的。我使用带有 Debian OS(2.6.32-5 内核)的 4 核 64 位机器。有人可以帮助我了解和解决这种情况吗? 下面描述了上述问题的一些插图。

【问题讨论】:

当您说使用 100% cpu 时:是 1 个核心 100% 还是所有 4 个核心 100%?另外,当使用 100% 时,尝试 hook Jconsole 并检查哪些线程是可运行的,它真的是使用 cpu 的 GC 还是其他任何东西? 当我谈到 CPU 使用率时,我指的是所有 4 个核心的 CPU 使用率(包括 GC)。不幸的是,该应用程序位于远程服务器上(没有 GUI),我无法在那里运行一些带有图形界面的工具。请注意,我使用了从 Java MBean(如 JConsole)获取信息的自定义监视器。插图是从那里抓取的。 我也查看了 JMap 输出 - 没有任何阻塞或可疑线程。但是当我查看 HTop 输出时,我发现只有少数应用程序线程处于运行状态(而不是处于睡眠状态),并且每个线程都占用了大约 2-3% 的 CPU。但是有一个线程(我猜是 GC)的消耗率接近 100%(92-94%)。 一个 (gc) 线程不能吃掉 4 x 100% cpu,所以发生了其他事情。你可以在你的远程机器上做堆栈转储,看看哪个线程在做什么。 不是这样。我说的GC线程全部占用1个核心。请注意,GC 只会在切换到完整 GC 周期时这样做。 【参考方案1】:

令人惊讶的是,我检测到了奇怪的行为 - GC 开始时 完整的 gc 循环...

不幸的是,这并不令人意外,因为在 JVM 中实现的 G1 GC 只使用一个硬件线程 (vCPU) 来执行 Full GC,因此我们的想法是尽量减少 Full GC 的数量。请记住,建议将此收集器用于具有多个内核的配置(当然它不会影响 Full GC,但会影响分配和并行收集)以及我认为大于 8GB 的​​大堆。

根据甲骨文:

https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/g1_gc.html

Garbage-First (G1) 垃圾收集器是一种服务器式垃圾 收集器,针对具有大内存的多处理器机器。 它试图以较高的速度满足垃圾收集 (GC) 暂停时间目标 概率,同时实现高吞吐量。全堆操作, 例如全局标记,与 应用程序线程。这可以防止与堆成比例的中断 或实时数据大小。

在这篇文章中有一个关于这个收集器中的Full GC单线程的解释。

https://www.redhat.com/en/blog/part-1-introduction-g1-garbage-collector

最后不幸的是,G1 还必须处理可怕的 Full GC。虽然 G1 最终试图避免 Full GC,但它们仍然是 严酷的现实,尤其是在调整不当的环境中。 鉴于 G1 的目标是更大的堆大小,Full GC 的影响可能是 对飞行中的处理和 SLA 来说是灾难性的。初级之一 原因是 Full GC 在 G1 中仍然是单线程操作。 从原因来看,第一个也是最可以避免的,与 元空间。

顺便说一句,Java (10) 的最新版本似乎将包含一个能够并行执行 Full GC 的 G1。

https://www.opsian.com/blog/java-10-with-g1/

Java 10 通过迭代改进其完全 GC 暂停时间 现有算法。直到 Java 10 G1 Full GCs 在单线程中运行。 没错-您的 32 核服务器和 128GB 将停止并暂停 直到一个线程取出垃圾。

也许,您应该调整元空间或增加堆,或者您可以使用其他收集器,例如并行 GC。

【讨论】:

以上是关于Java 7 G1GC 奇怪的行为的主要内容,如果未能解决你的问题,请参考以下文章

等待/通知的奇怪java行为

iOS 7 上消息编辑器的奇怪行为

奇怪的行为 - 序列化

从Java访问元组的奇怪行为

在 Python2.7 中比较 Timestamp 和 datetime64 时的奇怪行为

Windows 7 上的奇怪行为 QT QSerialPort 不会更改串行 com 端口的设置