12

深入JVM - Code Cache内存池

 4 years ago
source link: https://renfufei.blog.csdn.net/article/details/115165919
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

深入JVM - Code Cache内存池

1. 本文内容

本文简要介绍JVM的 Code Cache(本地代码缓存池)。

2. Code Cache 简要介绍

简单来说,JVM会将字节码编译为本地机器码,并使用 Code Cache 来保存。
每一个可执行的本地代码块,称为一个 nmethod。
nmethod 可能对应一个完整的Java方法,或者是内联后的方法。

即时编译器(just-in-time,JIT)是代码缓存区的最大消费者,所以此区域又被开发者称为 JIT code cache。

3. 对 Code Cache 进行调优

code cache 区域的大小是固定的。

如果Code Cache区域用满了,就会停止JIT编译, 也就是说JVM不再编译任何代码。
我们还会收到 “CodeCache is full… The compiler has been disabled” 之类的告警消息。
JIT编译器关闭的结果,就是系统性能急剧下降。
为了避免这种情况,我们需要对Code Cache进行调优,例如使用以下参数:

  • InitialCodeCacheSize – 初始大小, 默认值为 160KB
  • ReservedCodeCacheSize – 保留给Code Cache的空间, 也就是最大空间, 默认值: 48MB
  • CodeCacheExpansionSize – 每次扩充的大小, 一般为 32KB 或者 64KB

合理地增加 ReservedCodeCacheSize 是一种解决办法, 毕竟现在很多应用加上依赖库的代码量一点都不少。
但我们也不能无限制地增大这个区域的大小。

幸运的是,JVM提供了一个启动参数 UseCodeCacheFlushing, 用来控制Code Cache的刷新。 这个参数的默认值为 false
如果将其开启(-XX:+UseCodeCacheFlushing),则会在满足以下条件时释放占用的区域:

  • code cache用满; 如果该区域的大小超过某个阈值,则会刷新。
  • 自上次清理后经过了一定的时间间隔。
  • 预编译的代码不够热。 对于每个JIT编译的方法,JVM都会有一个热度跟踪计数器。 如果计数器的值小于动态阈值,则JVM会释放这段预编译的代码。

提示: 除非Code Cache不够用了,否则不要乱开;

4. 查看Code Cache的使用情况

想要监控代码缓存的使用情况,我们可以跟踪当前使用的内存大小。

指定JVM启动参数: –XX:+PrintCodeCache, 会打印Code Cache区的使用情况。
程序执行过程中, 我们可以看到类似下面的输出:

CodeCache: size=32768Kb used=542Kb max_used=542Kb free=32226Kb

一起来分析下各个部分数值的含义:

  • size 表示此内存区域的最大值,与 ReservedCodeCacheSize 相等。
  • used 是此区域当前实际使用的内存大小。
  • max_used 是程序启动以来的历史最大使用量
  • free 是此区域尚未使用的空闲空间

PrintCodeCache 选项非常有用,可以帮助我们:

  • 查看何时进行了刷新(flushing)
  • 确定内存使用量是否达到关键点位

5. Code Cache分段

从Java 9开始,JVM将 Code Cache 细分为三个不同的段,每个段包含一种类型的编译代码。
具体是:

  • 非方法段(non-method segment), 保存相关的JVM内部代码,例如字节码解释器。 默认情况下,此段约为 5 MB。 可通过 -XX:NonNMethodCodeHeapSize 参数进行调整。
  • 待分析代码段(profiled-code segment), 包含经过简单优化的代码,使用寿命很短。 此段的大小默认为 122 MB,可以通过 -XX:ProfiledCodeHeapSize 参数进行调整。
  • 静态代码段(non-profiled segment), 保存经过全面优化的本地代码,使用寿命可能很长。 默认大小同样是 122 MB。 可以通过-XX:NonProfiledCodeHeapSize 参数进行调整。

这种新的分段结构,以不同方式处理各种类型的编译代码,整体上具有更好的性能。

例如,将已编译的短命代码和长寿代码分开,提高方法清除器的性能 - 毕竟需要扫描的内存区域变小了。

本文简要介绍了JVM的Code Cache内存区域。

也介绍了一些监视和诊断此内存区使用情况的方法,以及相关的优化和配置选项。


Recommend

  • 12
    • blog.zzhpro.com 4 years ago
    • Cache

    深入理解 JVM 内存结构

    深入理解 JVM 内存结构 Never really desperate, only the lost of the soul. ...

  • 14
    • www.daqianduan.com 4 years ago
    • Cache

    JVM 源码分析(三):深入理解 CAS

    前言 什么是 CAS Java 中的 CAS JVM 中的 CAS 在上一篇文章中,我们完成了源码的编译和调试环境的搭建。

  • 6
    • renfufei.blog.csdn.net 4 years ago
    • Cache

    深入JVM - 实例详解invoke相关操作码

    深入JVM - 实例详解invoke相关操作码 Java...

  • 16
    • 微信 mp.weixin.qq.com 4 years ago
    • Cache

    万字完整深入解析JVM 面试必备

    来源:https://segmentfault.com/a/1190000014395186                                    工作之余,想总...

  • 11
    • nanyiniu.github.io 4 years ago
    • Cache

    深入JVM(二)JVM垃圾回收器

  • 11
    • nanyiniu.github.io 4 years ago
    • Cache

    深入JVM(三)JVM调优

    ¶ 参数分类 在多数项目中不需要进行JVM调优,在出现OOM或CPU飙高,往往是程序...

  • 7

  • 8
    • segmentfault.com 4 years ago
    • Cache

    深入理解JVM - 实战老年代优化

    深入理解JVM - 实战老年代优化​ 通过前面的文章可以了解到JVM优化中老年代的FULL GC对于系统以及垃圾收集器的行为有着十分大的影响,比如CMS并发标记或者回收撑不住的时候要暂停用户线程并且呼叫serrial收集器帮忙进行单线程的高效回收的动作,但是...

  • 4
    • segmentfault.com 4 years ago
    • Cache

    深入理解JVM - CMS收集器

    深入理解JVM - CMS收集器​ 上一节我们讲解分代和垃圾回收算法,这一节我们来讲解老年代重要的垃圾收集器:cms收集器。这一节的内容同样比较多。​ 这一节主要围绕着十分常用的CMS垃圾收集器进行讲解。​ 上一篇文章我们讲解分代...

  • 13
    • segmentfault.com 4 years ago
    • Cache

    深入理解JVM - 实战JVM工具(下)

    深入理解JVM - 实战JVM工具(下)​ 接着上篇继续讲述,上一篇模拟了两个还算比较熟悉的场景,分析了之前老年代优化是如何处理的,以及使用jstat分析工具如何分析出JVM的问题,这一节会继续扩展,将会列举更多的案例来分析线上的JVM问题。​...

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK