CodeCache不足导致应用load偏高的问题

CodeCache 是用来保存由JIT 产生的native code 的内存区域,它是独立于JVM heap的非堆内存。

JIT(just-in-time)编译(HotSpot),是指在运行时,把频繁执行的 bytecode 转换成操作系统相关的机器码,这样程序执行时就不需要解释执行,可以提高程序性能,具体可以看下这个博客。

 

问题描述:

我想在应用里面试用一下greys, 当使用monitor 功能时,发现load飙高,数据库连接池撑爆,应用立即无法响应,吓死宝宝了。随即关掉greys,恢复了应用。之后我联系了作者,他说有可能是我们应用CodeCache不足,导致JIT 回收CodeCache时,占满cpu。

 

原因定位:

因为集团其他同事也遇到过此类问题,他用的是aliperf来定位热点代码,最后定位到JVM的largest_free_block()函数。简单的说,JVM在维护CodeCache时会维护一个freelist(空闲内存块的链表),当要分配空间时,会遍历这个freelist。而采用分层编译时会导致编译后的代码被频繁的写入或失效CodeCache,freelist变的非常碎片化,非常长,而每次JVM进行JIT操作时,会持有锁并且遍历这个list,看源码,可以看到持有了锁。

 1 size_t CodeCache::largest_free_block() {
 2   // This is called both with and without CodeCache_lock held so
 3   // handle both cases.
 4   if (CodeCache_lock->owned_by_self()) {
 5     return _heap->largest_free_block();
 6   } else {
 7     MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
 8     return _heap->largest_free_block();
 9   }
10 }

因此load变高,引发了后续一系列问题。jdk官方也有类似bug,在jdk8中修复。

验证:

 首先我查了下我们应用默认的CodeCache大小。

1 jinfo -flag ReservedCodeCacheSize 

发现是50M,然后通过jmx查看了在应用运行中使用的CodeCache大小,发现用了48M,果然已经接近极限。

greys采用了动态代理,在runtime时产生大量代理类,被编译写入CodeCache,导致CodeCache空间不足,成为最后一根稻草。

总结:

可以看到真正的原因有两部分组成,

1. CodeCache 空间不足,引发JVM回收空间,调用largest_free_block()。

2. JVM 采用了分层编译,编译器采用了C1、C2两种编译方式,CodeCache中会存在C1和C2编译过的代码

不分层编译就只有C2编译过的代码,使得CodeCache更容易填满。

问题解决:

通过添加-XX:ReservedCodeCacheSize=512M 更改CodeCache大小。

通过添加 -XX:+UseCodeCacheFlushing 使得CodeCache在接近满时,释放一半Cache,参考文章。

 

 

转载于:https://www.cnblogs.com/rsdyxjh/p/4762320.html

你可能感兴趣的:(CodeCache不足导致应用load偏高的问题)