本文阅读时间大约5分钟。

有业务反馈,线上一个应用运行了一段时间之后,在高峰期之后,突然发现处理能力下降,接口的响应时间变长,但是看Cat上的GC数据,一切都很正常。

通过跳板机上机器查看日志,发现一段平时很少见到的日志:

Java HotSpot(TM) 64-Bit Server VM warning: CodeCache is full. Compiler has been disabled.
Java HotSpot(TM) 64-Bit Server VM warning: Try increasing the code cache size using -XX:ReservedCodeCacheSize=.
...
“CompilerThread0” java.lang.OutOfMemoryError: requested 2854248 bytes for Chunk::new. Out of swap space?

其中CodeCache is full,说明Code Cache已经满了,导致Compiler失效,这是为什么?

首先,我们得了解什么是Code Cache。

什么是Code Cache

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

Code Cache 调优

由于Code Cache是一块内存区域,那么肯定有大小的限制,但是不同版本的JVM、不同的启动方式,Code Cache的默认大小也不同,可通过 jinfo-flagReservedCodeCacheSize 进行查看。

服务启动之后,随着时间的推移,肯定会有越来越多的方法被JIT编译成本地机器码,并存放到Code Cache,由于Code Cache大小是固定的,那么就存在被用完的风险。

一旦Code Cache被填满,就会出现下面情况:

  • JVM的JIT功能会被停止,将不会编译任何额外的代码。

  • 被编译过的代码仍然以编译方式执行,但是尚未被编译的代码只能以解释方式执行了。

这种情况下,如果应用中还有很多代码以解释方式执行,其性能会大大降低。为了避免这种情况,就需要对Code Cache比较深入的理解。

JVM启动的时候,Code Cache所需内存会被单独初始化,这时候Java堆还会被初始化,所以Code Cache和Java堆是两块独立内存区域。

codeCache.cppCodeCache::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以后的版本已经得到修复。

下方查看历史文章

通过SOFA看Java服务端如何实现运行时的模块化

JVM调优实战:G1中的to-space exhausted问题

MAT入门到精通(一)

MAT入门到精通(二)

本号专注于后端技术、JVM问题排查和优化、Java面试题、个人成长和自我管理等主题,为读者提供一线开发者的工作和成长经验,期待你能在这里有所收获。

JVM Code Cache空间不足,导致服务性能变慢的更多相关文章

  1. JVM内存区域详解(Eden Space、Survivor Space、Old Gen、Code Cache和Perm Gen)

    JVM区域总体分两类,heap区和非heap区.heap区又分为: Eden Space(伊甸园). Survivor Space(幸存者区). Old Gen(老年代). 非heap区又分: Cod ...

  2. JVM虚拟机20:内存区域详解(Eden Space、Survivor Space、Old Gen、Code Cache和Perm Gen)

    1.内存区域划分 根据我们之前介绍的垃圾收集算法,限定商用虚拟机基本都采用分代收集算法进行垃圾回收.根据对象的生命周期的不同将内存划分为几块,然后根据各块的特点采用最适当的收集算法.大批对象死去.少量 ...

  3. 使用Django.core.cache操作Memcached导致性能不稳定的分析过程

    使用Django.core.cache操作Memcached导致性能不稳定的分析过程 最近测试一项目,用到了Nginx缓存服务,那可真是快啊!2Gb带宽都轻易耗尽. 不过Api接口无法简单使用Ngin ...

  4. 小师妹学JVM之:cache line对代码性能的影响

    目录 简介 一个奇怪的现象 两个问题的答案 CPU cache line inc 和 add 总结 简介 读万卷书不如行万里路,讲了这么多assembly和JVM的原理与优化,今天我们来点不一样的实战 ...

  5. 记我的一次 Java 服务性能优化

    背景 前段时间我们的服务遇到了性能瓶颈,由于前期需求太急没有注意这方面的优化,到了要还技术债的时候就非常痛苦了. 在很低的 QPS 压力下服务器 load 就能达到 10-20,CPU 使用率 60% ...

  6. 一个网关服务性能问题的Dump分析

    本篇文章分为三部分,首先简单介绍一下分析的工具Windbg,其次针对一个网关服务性能问题进行逐步刨析,最后针对性能问题的分析总结. 一 Windbg介绍 1.Windbg是个非常强大的调试器,它设计了 ...

  7. 解决ArcGIS中因SDE或数据库配置问题而导致服务宕掉的一种思路

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.背景 最近连续有两个项目现场出现了AGS服务荡掉的问题,一个是通州 ...

  8. log4j导致的性能问题

    问题背景 双十一零点时,有一个服务A(后文该服务都用A来代替)的tp99由平常的50ms左右突然彪到60000ms,导致调用端积累了几十W的数据,同时,也影响到了同一个docker上的其他服务.那为什 ...

  9. Tomcat9.0.13 Bug引发的java.io.IOException:(打开的文件过多 Too many open files)导致服务假死

    问题背景: 笔者所在的项目组最近把生产环境Tomcat迁移到Linux,算是顺利运行了一段时间,最近一个低概率密度的(too many open files)问题导致服务假死并停止响应客户端客户端请求 ...

随机推荐

  1. 修改woocommerce列表产品显示数量

    WooCommerce列表产品数量默认显示为10,如果是显示3列或4列,则最后一行会有空白留出,为了美观,往往我们要设置显示合适的产品数量.因此,只要把如下代码复制到当前主题的functions.ph ...

  2. zz:一个框架看懂优化算法之异同 SGD/AdaGrad/Adam

    首先定义:待优化参数:  ,目标函数: ,初始学习率 . 而后,开始进行迭代优化.在每个epoch  : 计算目标函数关于当前参数的梯度:  根据历史梯度计算一阶动量和二阶动量:, 计算当前时刻的下降 ...

  3. javaweb监听器实现与原理

    参考:https://www.cnblogs.com/lxp503238/p/6678688.html https://blog.csdn.net/CPOHUI/article/details/888 ...

  4. oracle sql语言模糊查询

    '^' 匹配输入字符串的开始位置,在方括号表达式中使用,此时它表示不接受该字符集合.'$' 匹配输入字符串的结尾位置.如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配 '\n ...

  5. Excel-查找函数

    1.VLOOKUP函数 该函数的语法规则如下: VLOOKUP(lookup_value,table_array,col_index_num,range_lookup) 多表关联查询---vlooku ...

  6. 成神之Java之路

    既然励志在java路上走的更远,那就必须了解java的路径.先看图 image.png 更加细化的细节如下 一: 编程基础 不管是C还是C++,不管是Java还是PHP,想成为一名合格的程序员,基本的 ...

  7. hzoi欢乐时刻(持续更新)

    %%NC哥 %%Dybala %%cbx吐露(bei ji can)真相 %%skyh×2 不愿透露姓名的群众无意间发现惊人秘密, skyh默默坦白真相, 这究竟是人性的沦丧还是道德的泯灭? %%kx ...

  8. 学习vue_01

    目录 vue 框架: 框架介绍 基础格式 插值表达式: 文本指令: 事件指令: 属性指令: 小结: js 补充(面向对象): vue 框架: --构建虚拟的DOM结构,(内存内改变对象)- 操作数据的 ...

  9. FWT-快速沃尔什变换

    FWT-快速沃尔什变换 FWT有啥用啊 我们知道,FFT可以解决多项式的卷积,即 \[ C_k=\sum_{i+j=k}A_i*B_j \] 如果将操作符换一下,换成集合运算符 比如 \[ C_k=\ ...

  10. 企业级Nginx负载均衡与keepalived高可用实战(二)keepalived篇

    1.Keepalived高可用软件 1.1.Keepalived介绍 Keepalived软件起初是专门为LVS负载均衡软件设计的,用来管理并监控LVS集群系统中各个服务节点的状态,后来又加入了可以实 ...