• jstack: Java占用高CPU分析之- C2 CompilerThread

    1. 现象

    应用刚上线时发现Java进程占用了大量的CPU份额,但过了几分钟后会降下来(流量没变的情况下),因为已经做了负载均衡,于是拿一台实例重新部署代码上线来分析。具体分析步骤参考另外一篇文章《jstack: Java占用高CPU分析之- GC task thread》。这里简单说一下步骤,重点是分析结果后的解决方法,不过强调一点:当发现Java应用占用高CPU的时候,先把Java的线程号和JVM的堆栈信息记录到文件(这个可以用脚本实现),因为堆栈信息随时在变

     

    2.定位

    top | grep java

    cpu2_1

    cpu2_2

    cpu2_3

    cpu2_4

     

    3.原因和解释

    定位到 C2 CompilerThread0这个线程占用了比较高的CPU。C2 Compiler 是JVM在server模式下字节码编译器,JVM启动的时候所有代码都处于解释执行模式,当某些代码被执行到一定阈值次数,这些代码(称为热点代码)就会被 C2 Compiler编译成机器码,编译成机器码后执行效率会得到大幅提升。

    流量进来后,大部分代码成为热点代码,这个过程中C2 Compiler需要频繁占用CPU来运行,当大部分热点代码被编译成机器代码后,C2 Compiler就不再长期占用CPU了,这个过程也可以看作抖动。

    4.解决方案

    (1)最直接有效的方法是“预热(warm up)”:可以使用Jmeter等压测工具模拟线上访问流量,让C2 Compiler预先将热点代码编译成机器码, 减少对正式环境流量的影响。

    warmup

    (2) 设置JVM启动参数:-XX:CICompilerCount=threads

    默认是2, 可以设置4或6。在默认值下抖动时CPU已经满载,设置成更多的线程也不一定起作用,但对于CPU“高而不满”的情况会有用,能减少抖动时间。

    CICompilerCount

     

    参考文章:

    http://www.javaworld.com/article/2078635/enterprise-middleware/jvm-performance-optimization-part-2-compilers.html

    https://answers.atlassian.com/questions/22651310/c1c2-compiler-thread-eats-a-lot-of-cpu

    http://www.cnblogs.com/LBSer/p/3703967.html

    http://qa.blog.163.com/blog/static/190147002201392221426372/

    https://docs.oracle.com/javase/8/docs/technotes/tools/windows/java.html