问题描述
近期在项目维护中,生产机器存在服务器的CPU占比很高的问题,经过确证是C2 CompilerThread CPU占比很高。C2线程调用栈如下所示:

...
Thread 1 (process 68):
#0 0xf6abda90 in MemBarCPUOrderNode::Opcode() const () from /usr/java/jdk1.8.0_152/jre/lib/i386/server/libjvm.so
#1 0xf6e8462c in MemNode::can_see_stored_value(Node*, PhaseTransform*) const () from /usr/java/jdk1.8.0_152/jre/lib/i386/server/libjvm.so
#2 0xf6e84afb in LoadNode::Value(PhaseTransform*) const () from /usr/java/jdk1.8.0_152/jre/lib/i386/server/libjvm.so
#3 0xf6f5368a in PhaseIterGVN::transform_old(Node*) () from /usr/java/jdk1.8.0_152/jre/lib/i386/server/libjvm.so
#4 0xf6f51084 in PhaseIterGVN::optimize() () from /usr/java/jdk1.8.0_152/jre/lib/i386/server/libjvm.so
#5 0xf6aece24 in Compile::Optimize() () from /usr/java/jdk1.8.0_152/jre/lib/i386/server/libjvm.so
#6 0xf6aeea0a in Compile::Compile(ciEnv*, C2Compiler*, ciMethod*, int, bool, bool, bool) () from /usr/java/jdk1.8.0_152/jre/lib/i386/server/libjvm.so
#7 0xf6a43a4d in C2Compiler::compile_method(ciEnv*, ciMethod*, int) () from /usr/java/jdk1.8.0_152/jre/lib/i386/server/libjvm.so
#8 0xf6af92b1 in CompileBroker::invoke_compiler_on_method(CompileTask*) () from /usr/java/jdk1.8.0_152/jre/lib/i386/server/libjvm.so
#9 0xf6afa0c7 in CompileBroker::compiler_thread_loop() () from /usr/java/jdk1.8.0_152/jre/lib/i386/server/libjvm.so
#10 0xf7031f48 in compiler_thread_entry(JavaThread*, Thread*) () from /usr/java/jdk1.8.0_152/jre/lib/i386/server/libjvm.so
#11 0xf703cadf in JavaThread::thread_main_inner() () from /usr/java/jdk1.8.0_152/jre/lib/i386/server/libjvm.so
#12 0xf703cc5b in JavaThread::run() () from /usr/java/jdk1.8.0_152/jre/lib/i386/server/libjvm.so
#13 0xf6f0c179 in java_start(Thread*) () from /usr/java/jdk1.8.0_152/jre/lib/i386/server/libjvm.so
#14 0xf77b8b2c in start_thread () from /lib/libpthread.so.0
#15 0xf76cf17e in clone () from /lib/libc.so.6
可以看出cpu一直在MemNode::can_see_stored_value函数内循环。
问题解决思路
完全禁用C2编译器。我们可以通过提供-XX:TieredStopAtLevel=1 Java选项来实现这一点。这个选项可以解决空闲状态下的CPU消耗,因此它验证了我们关于C2导致问题的假设。然而,这种变通方法可能对生产系统无效和/或不可取,因为它禁用了复杂的C2编译器,因此可能会导致应用程序性能大大降低。
class ciMethod : public ciMetadata {
...
private: // General method information.
ciFlags _flags;
ciSymbol* _name;
ciInstanceKlass* _holder;
ciSignature* _signature;
...
}
结合openjdk中C2编译器源码观察上图,在第7帧中有ciMethod参数,我们可以抓取core文件,通过gdb和hsdb命令分析core.dump文件,获取compile_method()函数的入参。通过该入参可知具体是在哪个方法进行C2编译时导致死循环。可通过以下java选项将该方法添加到排除列表中。
-XX:CompileCommand=XXXXXX::xxxxxx
886

被折叠的 条评论
为什么被折叠?



