当前位置: 首页 > article >正文

类指针压缩空间

一、类指针压缩介绍

压缩指针,指的是在 64 位的机器上,使用 32 位的指针来访问数据(堆中的对象或 Metaspace 中的元数据)的一种方式。

对象头中的 Class Pointer 默认占 8 个字节,开启 -XX:+UseCompressedOops 后,为了节省空间压缩为 4 个字节,Java 堆中对象指针会被压缩成 32 位,使用堆基地址(如果堆在低 26G 内存中的话,基地址为 0)。如果堆内存超过 32GB(JVM 是 8 字节对齐),那么压缩指针会失效,因为 32G 内存后,压缩就没有多大必要了,要管理那么大的内存指针也需要很大的宽度。在堆内存小于 32G 时,可以通过编码、解码方式进行优化,使得 JVM 可以支持更大内存配置。当堆内存空间大于 32G 时,压缩指针参数可能会失效,会强制使用 64 位(即 8 字节)来对 Java 对象寻址了。

#开启指针压缩:
-XX:+UseCompressedOops
#关闭指针压缩:
-XX:-UseCompressedOops

但是这个 32GB 是和字节对齐大小相关的,也就是 -XX:ObjectAlignmentInBytes 配置的大小(默认是 8 字节,Java 默认是 8 字节对齐)。-XX:ObjectAlignmentInBytes 可以设置为 8 的整数倍,最大 128,如果设为 24,那么配置最大的堆内存超过 96GB 压缩之指针会失效。

二、_mark 和 _klass 指针

JVM 中,每个对象都有一个指向它自身类的指针,不过这个指针只是指向具体的实现类,而不是接口或者抽象类。只有是 64 位平台上启用了类指针压缩才会存在这个区域。对于 64 位平台,为了压缩 JVM 对象中的 _klass 指针的大小,引入类指针压缩空间(Compressed Class Pointer Space)

_mark:mark word 一组标记,描述了对象的状态,包括对象默认哈希值(如果没有覆盖默认的 hashCode 方法,则哈希值在 hashCode 方法被调用之后,会被记录到 MarkWord 之中)、对象的形状(是否是数组)、锁状态(偏向锁等锁信息,偏向锁在 Java 15 中废弃:Disable and Deprecate Biased Locking)、数组长度(如果标记显示这个对象是数组,描述了数组的长度)。MarkWord 的实现仅仅包含一个 uintptr_t 类型,所以,在 32 位和 64 位虚拟机上面,大小分别是 4 字节和 8 字节。

_klass:是指向对象实现的 Class 的指针。JDK7 之前指向的区域位于持久带(Permanent Generation),JDK8 之后,永久代带废弃,引入了元数据区的概念(Metaspace),所以 JDK8 之后指向的是这个元数据区。这个指针可能是被压缩的,即压缩指针(Compressed OOPs)。当开启对象压缩时占用 4 字节(JVM默认开启),关闭时占用 8 字节

class oopDesc {
    private:
    volatile markWord _mark; // 对象头 mark word
    union _metadata {
        Klass*      _klass; // 类型指针:执行类的指针
        narrowKlass _compressed_klass;
    } _metadata;
}
class markWord {
 private:
  uintptr_t _value;
}
  1. 32 位的 JVM:​​​​​​​
    1. _mark:4 字节。mark word
    2.  _klass:4 字节。指向类的指针,对象的内存布局中的第二个字段(_klass,在 32 位 JVM 中,相对对象内存的位置的偏移量是 4,64 位的是 8)指向的是内存中对象的类定义
  2. 64 位的 JVM:​​​​​​​​​​​​​​
    1. _mark:8 字节
    2. _klass:8 字节
  3. 开启了指针压缩的 64 位的 JVM:
    1.  _mark:8 字节
    2. _klass:4 字节

三、类指针压缩空间

JDK1.8 移除了 permanent generation,class metadata 存储在 native memory (meta space)中,其大小默认是不受限的,可以通过 -XX:MaxMetaspaceSize 来限制。

在 JVM 使用 -XX:+UseCompressedClassPointers 和 -XX:+UseCompressedOops 开启 Compressed Class 的功能后,会在 Metaspace 中开辟出一块新的空间(Compressed Class Space),这个空间不足会出现了 OOM,可以通过设置 -XX:CompressedClassSpaceSize(默认值为1G) 的大小或者 -XX:-UseCompressedClassPointers 来关闭该功能。

如果开启了-XX:+UseCompressedOops 及 -XX:+UseCompressedClassesPointers(默认开启),则UseCompressedOops 会使用 32-bit 的 offset 来代表 java object 的引用,而 UseCompressedClassPointers 则使用32-bit 的 offset 来代表 64-bit 进程中的 class pointer。可以使用 CompressedClassSpaceSize 来设置这块的空间大小,CompressedClassSpace 分配在 MaxMetaspaceSize 里头,即 MaxMetaspaceSize = CompressedClassSpaceSize + Metaspace area (excluding the Compressed Class Space) Size,压缩指针后的内存布局:

指针压缩概要

  1. 64 位平台上默认打开
  2. 使用 -XX:+UseCompressedOops 压缩对象指针
    1. oops 指的是普通对象指针(ordinary object pointer)
    2. Java 堆中对象指针会被压缩成 32 位
    3. 使用堆基地址(如果堆内存低于 26G 时,基地址为 0),即指针的偏移量针对于堆的基地址
  3. 使用 -XX:+UseCompressedClassPointers 选项来压缩类指针
    1. 对象中指向类元数据的指针会被压缩成32位
    2. 使用类指针压缩空间的基地址

四、元空间和类指针压缩空间的区别

类指针压缩空间只包含类的元数据,比如 InstanceKlass, ArrayKlass 仅当打开了 UseCompressedClassPointers 选项才生效。为了提高性能,Java 中的虚方法表也存放到这里。元空间包含类的其它比较大的元数据,比如方法,字节码,常量池(类常量池、运行时常量池)等。


http://www.kler.cn/a/148458.html

相关文章:

  • C++初阶:类和对象(上)
  • vue2+ element ui 集成pdfjs-dist
  • 用vscode编写verilog时,如何有信号定义提示、信号定义跳转(go to definition)、模块跳转这些功能
  • POI实现根据PPTX模板渲染PPT
  • 常用的Anaconda Prompt命令行指令
  • 轻松上手:使用Docker部署Java服务
  • 【Vue】图片切换
  • 【视觉SLAM十四讲学习笔记】第三讲——四元数
  • 一些关于开关电源经典回答
  • Java面向对象第6天
  • C 标准库 - <stdlib.h>和<string.h>详解
  • 基于mvc的大学生家教信息网站系统php+vue
  • INFINI Gateway 与华为鲲鹏完成产品兼容互认证
  • 5.golang字符串的拆解和拼接
  • 耗时一个星期整理的APP自动化测试工具大全
  • 【网络】传输层 --- 详解TCP协议
  • lv11 嵌入式开发 WDT实验 12
  • C语言:输入10个整数,写一个函数将其中最小的数和第一个数对换,把最大的数和最后一个数对换。(指针)
  • 14 网关实战:网关聚合API文档
  • 基于51单片机冰箱温度控制器设计
  • Sass混合器的详细使用教程
  • squid代理服务器(传统代理、透明代理、反向代理、ACL、日志分析)
  • ESP32-Web-Server编程- JS 基础 3
  • NFS 速度变慢问题排查 性能优化
  • 6、信息收集(1)
  • 23种设计模式之C++实践