Code Cache满导致接口性能变慢

来源:互联网 发布:删除淘宝中差评的公司 编辑:程序博客网 时间:2024/05/21 14:30

现象

一个系统在允许一段时间后 ,突然处理能力下降. 但是从流量, jstack. gc上看基本正常.
感觉好像 突然从健康状态 进入了了 虚弱状态.

原因

JDK7u4版本针对CodeCache有bug. JDK8以上修复.
UseCodeCacheFlushing 默认开启.
开启了TiredCompilation, 会导致占用CodeCache增大.
如果超出CodeCache的size限制,会触发:
1. 停止新Jit,直到有空间;
2. 启动CodeCache清理, 释放空间, 一定条件下会导致JIT被关闭

排查

这个问题,可以排查GC日志:从 gc 日志里面搜下面的关键词,jdk6才会打出这个信息,jdk7版本不会.

VM warning: CodeCache is full. Compiler has been disabled.

可以使用命令检查一下Code Cache的值。使用命令:

jinfo -flag ReservedCodeCacheSize

背景知识

JIT

在Java中提到“编译”,自然很容易想到Javac编译器将.java文件编译成为.class文件的过程,这里的Javac编译器称为前端编译器,其他的前端编译器还有诸如Eclipse,JDT中的增量式编译器ECJ等。相对应的还有后端编译器,它在程序运行期间将字节码转变成机器码(现在的Java程序在运行时基本都是解释执行加编译执行),如HotSpot虚拟机自带的JIT(Just In Time Compiler)编译器(分Client端和Server端)

Java程序最初是仅仅通过解释器解释执行的,即对字节码逐条解释执行,这种方式的执行速度相对会比较慢,尤其当某个方法或代码块运行的特别频繁时,这种方式的执行效率就显得很低。于是后来在虚拟机中引入了JIT编译器(即时编译器),当虚拟机发现某个方法或代码块运行特别频繁时,就会把这些代码认定为“Hot Spot Code”(热点代码),为了提高热点代码的执行效率,在运行时,虚拟机将会把这些代码编译成与本地平台相关的机器码,并进行各层次的优化,完成这项任务的正是JIT编译器。

现在主流的商用虚拟机(如Sun HotSpot、IBM J9)中几乎都同时包含解释器和编译器(三大商用虚拟机之一的JRockit是个例外,它内部没有解释器,因此会有启动相应时间长之类的缺点,但它主要是面向服务端的应用,这类应用一般不会重点关注启动时间)。二者各有优势:当程序需要迅速启动和执行时,解释器可以首先发挥作用,省去编译的时间,立即执行;当程序运行后,随着时间的推移,编译器逐渐会返回作用,把越来越多的代码编译成本地代码后,可以获取更高的执行效率。解释执行可以节约内存,而编译执行可以提升效率。

运行过程中会被即时编译器编译的“热点代码”有两类:
被多次调用的方法。
被多次调用的循环体。

Code Cache

Code Cache用于存储JVM JIT产生的编译代码。如果应用需要编译大量的方法,那么会产生大量的编译代码( compiled code),然后会占满Code Cache。当Code Cache满了时,编译器停止进行方法的编译,并会打印下面的日志:

UseCodeCacheFlushing

开启UseCodeCacheFlushing这个参数,会在Code Cache满了时紧急进行清扫工作,它会丢弃一半老的编译代码(discards older half of the compiled code(nmethods) ,
参考: https://blogs.oracle.com/poonam/entry/why_do_i_get_message)。

开启UseCodeCacheFlushing导致问题 : CodeCache空间降了一半,方法编译工作仍然可能不会重启; flushing可能导致高的cpu使用,从而影响性能下降

参考wiki

http://blog.leanote.com/post/zenglingshu/%E4%B8%80%E4%B8%AART%E4%B8%8B%E9%99%8D%E7%9A%84%E5%A5%87%E6%80%AACase%5B%E8%BD%AC%5D

https://blogs.oracle.com/poonam/entry/why_do_i_get_message

http://hellojava.info/?tag=reservedcodecachesize

0 0
原创粉丝点击