L
L
LearnJava
Search…
CodeCache

一、简介

JVM生成的native code存放的内存空间称之为Code Cache;JIT(即时编译器)编译、JNI(Java本地接口)等都会编译代码到native code,其中JIT生成的native code占用了Code Cache的绝大部分空间,codecache是一块独立于Java堆之外的内存区域。
JIT:Java程序最初是仅仅通过解释器解释执行的,即对字节码逐条解释执行,这种方式的执行速度相对会比较慢,尤其当某个方法或代码块运行的特别频繁时,这种方式的执行效率就显得很低。于是后来 在虚拟机中引入了JIT编译器(即时编译器),当虚拟机发现某个方法或代码块运行特别频繁时,达到某个阈值,就会把这些代码认定为“Hot Spot Code”(热点代码),为了提高热点代码的执行效率,在运行时,虚拟机将会把这些代码编译成与本地平台相关的机器码,并进行各层次的优化,完成这项任务的正是JIT编译器。

二、作用

codecache用来将热点代码缓存起来,加快代码运行速度,服务启动之后,随着时间的推移,肯定会有越来越多的方法被JIT编译成本地机器码,并存放到Code Cache,由于Code Cache大小是固定的,那么就存在被用完的风险。一旦Code Cache被填满,就会出现下面情况:
  • JVM的JIT功能会被停止,将不会编译任何额外的代码。
  • 被编译过的代码仍然以编译方式执行,但是尚未被编译的代码只能以解释方式执行。
这种情况下,如果应用中还有很多代码以解释方式执行,其性能会大大降低。
在Speculative flushing开启的情况下,当Code Cache不足时:
  • 最早被编译的一半方法将会被放到一个old列表中等待回收;
  • 在一定时间间隔内,如果old列表中方法没有被调用,这个方法就会被从Code Cache清除;
很不幸的是,在JDK1.7中,Speculative flushing释放了一部分空间,但是从编译日志来看,JIT并没有恢复正常,并且系统整体性能下降很多,出现了大量超时。
在Oracle官网上看到这样一个Bug:http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8006952 由于算法问题,当Code Cache不足之后会导致编译线程无法继续,并且消耗大量CPU,导致系统运行变慢。

三、相关参数

# 查看JVM设置的codecache最大大小
jinfo -flag ReservedCodeCacheSize {pid}
# 或者
java -XX:+PrintFlagsFinal|grep --color CodeCache
# JVM启动参数
# 设置初始CodeCache大小
-XX:InitialCodeCacheSize
# 设置Reserved code cache的最大大小,通常默认是240M
-XX:ReservedCodeCacheSize=240M
# 是否在code cache满的时候先尝试清理一下,如果还是不够用再关闭编译,默认开启
-XX:+UseCodeCacheFlushing
# 关闭分层编译
-XX:-TieredCompilation
如果需要在运行时查看codecache大小,需要写段代码使用jmx查看,具体代码可以在最后的参考里面查看

四、codecache回收策略

如果满足以下条件之一则进行回收:
1)codecache满了;
2)从上次扫描到现在,存在codecache最大值1%的“状态变更的代码”;
状态变更?
  • alive -> not_entrant(存活->新进入)
  • not_entrant -> zombie(新进入->僵尸)
  • zombie -> marked_for_reclamation(僵尸->被标记为回收)
3)从上次扫描到一段时间内,codecache剩余的越多,越不容易触发回收。
回收会清理掉所有僵尸代码。如果 UseCodeCacheFlushing 打开的话还会清理非热点的存活代码。
非热点的存活代码?
  • 在每个safepoint每个活动的栈帧的热度值被置为默认值【2 * (codecache大小 / 1MB)】
  • 每次清理会将热度值-1
  • 当热度值小于一个阈值的时候会被判断为“非热点的存活代码”进而被清理,这个阈值和codecache的剩余百分比以及参数 -XX:NmethodSweepActivity 有关(默认值10),NmethodSweepActivity越大,codecache剩余百分比越小,那就越会被回收。
总结:codecache的清理时机和清理大小是在运行时动态决定的,影响因素包括:codecache总大小、剩余百分比,僵尸代码的数量,非热点存活代码的数量以及JVM的参数等。
Copy link
On this page
一、简介
二、作用
三、相关参数
四、codecache回收策略