引子

今日项目中将springboot的相关监控指标对接了promethues,在网上找了找到了“jvm-micrometer_rev9”的grafana的前端模板,测试同事说展示的信息都要测试,吓我一身冷汗,我只不过做了一些配置而已,好家伙到时候测试那么多,于是乎我就把“jvm-micrometer_rev9”中的一些展示不出来的指标给删了嘿嘿。堆内存相关的指标含义含义还是比较好理解的,主要就是Eden\Survivor\Old(大对象)区域。不过还是有一些堆外内存的指标含义不太清楚,所以对相关指标查询了一些资料,整理如下。

整体内存分布

下面这个图展示了JVM整体的内存空间布局

Java堆外内存框架 jvm堆外内存_JVM

metaspace

Metaspace 是用来存放 class metadata 的,class metadata 用于记录一个 Java 类在 JVM 中的信息,包括但不限于 JVM class file format 的运行时数据:
1、Klass 结构,可以理解为一个 Java 类在虚拟机内部的表示;
2、method metadata,包括方法的字节码、局部变量表、异常表、参数信息等;
3、常量池;
4、注解;
5、方法计数器,记录方法被执行的次数,用来辅助 JIT 决策;
6、 其他

Compressed Class Space

Java堆外内存框架 jvm堆外内存_sed_02

JVM中,每个对象都有一个指向它自身类的指针,不过这个指针只是指向具体的实现类(不是接口或者抽象类)。

对于32位的JVM:

_mark : 4字节常量

_klass: 指向类的4字节指针 对象的内存布局中的第二个字段( _klass,在32位JVM中,相对对象在内存中的位置的偏移量是4,64位的是8)指向的是内存中对象的类定义。

对于64位的JVM:

_mark : 8字节常量

_klass: 指向类的8字节的指针

对于64位平台,为了压缩JVM对象中的_klass指针的大小,引入了类指针压缩空间(Compressed Class Pointer Space)。

Java堆外内存框架 jvm堆外内存_JVM_03

所以 Compressed Class Space 是为了压缩JVM对象中的_klass指针的大小而专门引入的一个空间。
注意Compressed Class Space空间 + metaspace空间 <= MaxMetaspaceSize

non-method、profiled-code、non-profiled

JVM会将字节码编译为本地机器码,并使用 Code Cache 来保存,即时编译器(just-in-time,JIT)是代码缓存区的最大消费者,所以此区域又被开发者称为 JIT code cache。
non-method、profiled-code、non-profiled 这三个部分是Code Cache细分的三个不同的段:
非方法段(non-method segment), 保存相关的JVM内部代码,例如字节码解释器。 默认情况下,此段约为 5 MB。 可通过 -XX:NonNMethodCodeHeapSize 参数进行调整。
待分析代码段(profiled-code segment), 包含经过简单优化的代码,使用寿命很短。 此段的大小默认为 122 MB,可以通过 -XX:ProfiledCodeHeapSize 参数进行调整。
静态代码段(non-profiled segment), 保存经过全面优化的本地代码,使用寿命可能很长。 默认大小同样是 122 MB。 可以通过-XX:NonProfiledCodeHeapSize 参数进行调整。

DirectBuffer 和 MappedByteBuffer

都是NIO中的缓冲区