我一直在对我的应用程序进行基准测试并使用JMC进行分析.我注意到在负载下,它执行了相当多的JIT编译.如果我每秒发送大量事务,则编译时间会激增.编译时间总是与针对应用程序的任何重负载测试成比例增长.
我还观察到代码缓存也慢慢上升.所以我决定将代码缓存保留提高到500MB进行测试.不好动!现在它花费更多时间执行JIT.
然后我通过-XX:-UseCodeCacheFlushing显式禁用了代码缓存刷新.但是,我注意到代码缓存的峰值使用率大于当前大小.这引出了几个问题:
> JVM是否尝试缓存每个JIT编译?
>为什么即使禁用了刷新,峰值代码缓存大小也会大于当前大小?
>是否存在“临时”编译代码,在函数结束后自动删除?
最佳答案 在HotSpot JVM中,所有JIT编译的方法都保留在CodeCache中,直到它们被回收为止. UseCodeCacheFlushing影响冷(但仍然有效)编译方法的回收.但是,CodeCache还可能包含过时或无效的方法(“僵尸”),即使使用-XX:-UseCodeCacheFlushing,这些方法也会在下一个扫描周期进行清除.
>在tiered compilation模式(JDK 8以来的默认模式)中,可以使用不同的优化级别多次编译方法.一旦安装了方法的优化(第4层)版本,之前的版本就会过时,并且可以在完成该版本的所有激活后回收.
>当推测失败时(例如,在加载新类之后),推测编译的方法可能变得无效.这种方法也变成僵尸,以后可以回收.
>另一个示例是OSR compilation.这是一个方法的一个版本,专门用于在方法运行时将执行从解释器转移到已编译的代码.回答第3个问题,这是一种“临时”方法,在安装完整版本的编译方法并完成所有OSR激活后,该方法就会过时.
有一个单独的JVM标志-XX:-MethodFlushing来防止彻底扫描CodeCache,包括僵尸方法.