面试题:你简历中说你擅长JVM调优,给我一个关于Code Cache调优的案例吧。

本文转自公众号:占小狼的博客
 
问题描述有业务反馈,线上一个应用运行了一段时间之后,在高峰期之后,突然发现处理能力下降,接口的响应时间变长,但是看Cat上的GC数据,一切都很正常。
通过跳板机上机器查看日志,发现一段平时很少见到的日志。
  1. JavaHotSpot(TM)64-BitServer VM warning:CodeCacheis full.Compiler has been disabled.
  2. JavaHotSpot(TM)64-BitServer VM warning:Try increasing the code cache size using-XX:ReservedCodeCacheSize=.
  3. ...
  4. CompilerThread0 java.lang.OutOfMemoryError: requested 2854248 bytes forChunk::new.Out of swap space?
其中CodeCache is full,说明Code Cache已经满了,导致Compiler失效,这是为什么?
首先,我们得了解什么是Code Cache。

# 1、什么是Code Cache

Java代码在执行次数达到一个阈值会触发JIT编译,一旦代码块被编译成本地机器码,下次执行的时候会直接运行编译后的本地机器码。所以这本地机器码必须被缓存起来,而缓存这个本地机器码的内存区域就是Code Cache,它并不属于Java堆的一部分,除了JIT编译的代码之外,Java所使用的本地方法代码(JNI)也会存在codeCache中。

# 2、Code Cache 调优

由于Code Cache是一块内存区域,那么肯定有大小的限制,但是不同版本的JVM、不同的启动方式,Code Cache的默认大小也不同,可通过 jinfo -flag ReservedCodeCacheSize 进行查看。
服务启动之后,随着时间的推移,肯定会有越来越多的方法被JIT编译成本地机器码,并存放到Code Cache,由于Code Cache大小是固定的,那么就存在被用完的风险。
一旦Code Cache被填满,就会出现下面情况。
  • JVM的JIT功能会被停止,将不会编译任何额外的代码。
  • 被编译过的代码仍然以编译方式执行,但是尚未被编译的代码只能以解释方式执行了。
这种情况下,如果应用中还有很多代码以解释方式执行,其性能会大大降低。为了避免这种情况,就需要对Code Cache比较深入的理解。
JVM启动的时候,Code Cache所需内存会被单独初始化,这时候Java堆还会被初始化,所以Code Cache和Java堆是两块独立内存区域。
在 codeCache.cpp的 CodeCache::initialize()方法中,实现了Code Cache的初始化。
Code Cache包含了3种数据:
  • NonNMethodCode
  • ProfiledCode
  • NonProfiledCode
通过 SegmentedCodeCache参数可以选择按照整体初始化,还是分段初始化。
通过 -XX:ReservedCodeCacheSize参数可以指定Code Cache的初始化大小,这个默认值在不同的JDK版本也不同,目前我这边调试的是OpenJDK11,默认大小是240M,这个已经够用了。
可以看下其它版本的默认大小。
对于那些只有32M、48M的就可能存在Code Cache不足的隐患,增加 ReservedCodeCacheSize可以是一个解决方案,但这通常只是一个临时的解决方案。
幸运的是,JVM提供了一种比较激进的codeCache回收方式:Speculative flushing。
在JDK1.7.0_4之后这种回收方式默认开启,而之前的版本需要通过一个参数来开启: -XX:+UseCodeCacheFlushing
在Speculative flushing开启的情况下,当Code Cache不足时。
  • 最早被编译的一半方法将会被放到一个old列表中等待回收;
  • 在一定时间间隔内,如果old列表中方法没有被调用,这个方法就会被从Code Cache清除;
很不幸的是,在JDK1.7中,Speculative flushing释放了一部分空间,但是从编译日志来看,JIT并没有恢复正常,并且系统整体性能下降很多,出现了大量超时。
在Oracle官网上,有这样一个Bug:http://bugs.java.com/bugdatabase/viewbug.do?bugid=8006952 
由于算法问题,当Code Cache不足之后会导致编译线程无法继续,并且消耗大量CPU,导致系统运行变慢。
这个bug在7u101及8以后的版本已经得到修复。
本站所有文章均由网友分享,仅用于参考学习用,请勿直接转载,如有侵权,请联系网站客服删除相关文章。若由于商用引起版权纠纷,一切责任均由使用者承担
极客文库 » 面试题:你简历中说你擅长JVM调优,给我一个关于Code Cache调优的案例吧。

Leave a Reply

欢迎加入「极客文库」,成为原创作者从这里开始!

立即加入 了解更多