Java 7 G1GC奇怪行为

3
最近我尝试在我的Java处理器中使用来自jdk1.7.0-17的G1GC,该处理器正在处理从MQ接收到的大量相似消息(大约15-20个请求/秒)。每条消息都在单独的线程中处理(稳定状态下有约100个线程),由Java有限线程池提供服务。令人惊讶的是,当GC开始进行完整的gc循环时,它开始使用大量的处理时间(高达100%的CPU甚至更多)。我多次重构代码,目标是优化它并使其更加轻量级。但是没有任何显着结果-行为是相同的。我使用带有Debian操作系统(2.6.32-5内核)的4核64位机器。有人能帮助我理解和解决这种情况吗?下面是上述问题的一些插图。 enter image description here enter image description here enter image description here

当你说使用100%的CPU时,是指1个核心的100%还是4个核心全部都是100%?另外,在使用100%时,请尝试挂接Jconsole并检查哪些线程是可运行的,是真的GC在使用CPU还是其他什么东西? - bluevoid
当我谈论 CPU 使用率时,我的意思是所有 4 个核心的 CPU 使用率(包括 GC)。不幸的是,该应用程序位于远程服务器上(没有 GUI),我无法在那里运行带有图形界面的工具。请注意,我已经使用了自定义监视器,它从 Java MBeans(如 JConsole)获取信息。插图是从那里抓取的。 - user1856533
我也查看了JMap输出 - 没有任何被阻止或可疑的线程。但是当我查看HTop输出时,我发现只有少数我的应用程序线程处于运行状态(而不是睡眠状态),并且每个线程大约占用2-3%的CPU。但是有一个线程(我猜它是GC)占用近100%(92-94%)。 - user1856533
一个(gc)线程无法占用4个100%的CPU,所以肯定有其他问题。您可以在远程机器上执行堆栈转储并查看哪个线程正在执行什么操作。 - bluevoid
不是这样的。我所谈论的GC线程完全占用了一个核心。请注意,GC只在转换到完整的GC周期时才会这样做。 - user1856533
你能发一下你的JVM参数吗? - Ravindra babu
1个回答

0
令人惊讶的是,我发现了奇怪的行为 - 一旦GC开始完整的gc周期...

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

根据Oracle的说法:

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

垃圾优先(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产生灾难性的影响。其中一个主要原因是,在G1中,Full GC仍然是单线程操作。从原因上看,第一个也是最可避免的原因与Metaspace有关。
顺便说一下,似乎Java的最新版本(10)将包括具有并行执行Full GC功能的G1。

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

Java 10通过迭代改进现有算法来减少Full GC暂停时间。在Java 10之前,G1 Full GC在单个线程中运行。没错 - 您的32核服务器和其128GB内存将会停止和暂停,直到单个线程清理垃圾。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接