JVM -- 对象内存布局/指针压缩

本文详细介绍了JVM中对象内存布局的各个部分,包括对象头(Mark Word和类型指针)、实例数据和对齐填充,并讨论了指针压缩的实现原理和优势。针对不同类型的对象,如空对象、普通对象和数组对象,分析了它们在开启和关闭指针压缩情况下的内存占用。最后,探讨了如何计算对象大小以及在32G内存限制下如何通过调整对齐方式来扩展空间。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

对象内存布局

在这里插入图片描述

对象头
  • Mark Word
    ○ 32位占4B
    ○ 64位占8B
    ○ 哈希值
    ○ GC分代年龄
    ○ 锁状态标识
    ○ 偏向锁线程id
    ○ 偏向时间戳
  • 类型指针 Klass pointer
    ○ 对象所属的类的元信息的实例指针, instanceKlass在方法区的地址
    ○ 指针压缩优化
    ■ 开启 : 4B
    ■ 不开启 : 8B
  • 数组长度
    ○ 如果这个对象不是数组,占0B
    ○ 如果这个对象是数组,占4B
实例数据
  • 类的非静态属性,生成对象时就是实例数据
  • 相同长度的数据会放到一起,如long/duble
对齐填充
  • Java中所有的对象大小都是8字节对齐 8的整数倍
  • 如果一个对象占30B + JVM底层会补2B(对齐填充),凑成32字节,达到8字节对齐
  • 对齐填充补0 程序更好写 性能更高
  • 数组对象在关闭指针压缩的情况下会出现两端填充

指针压缩

  • jdk6以后引入的技术,默认是开启的,参数:-XX:+/-UseCompressedOops
  • 开启指针压缩可节省空间/寻址更高效
指针压缩的实现原理
  • 由于存在对齐填充,8字节对齐,二进制末尾都是 000
    ○ 8–> 1 000
    ○ 16–> 10 000
    ○ 24–> 11 000
    ○ 32–> 100 000
  • 指针压缩原理就是基于末尾三位000进行压缩
  • 存储的时候后三位000抹掉
  • 使用的时候后三位000补上,从而实现指针压缩

开启指针压缩的情况下,一个oop表示的最大对空间是多少

  1. 类型指针占4字节,也就是32位,一个oop,存储的时候是4B,32bit
  2. 使用的时候,尾部补了三个0, 35bit
  3. 即2的35次方=32G

32G不够用如何扩容

  1. 修改OpenJdk源码,调整8字节对齐(压缩抹掉后三位000,32G),调整为16位对齐(压缩抹掉后4位0000,64G)
  2. 目前CPU算力可能跟不上

计算对象大小

  • 用jol-core包或者HSDB都可以看,区别是HSDB只能看基于普通类生成对象的大小,java中的数组因为是运行时生成的,故它的大小只有运行时才能知晓。
  • 计算大小 : Mark Word + 类型指针 + 数组长度 + 实例数据 + 对齐填充
空对象(没实例数据)
  • 开启指针压缩 : 16B = 8B + 4B + 0B + 0B + 4B
  • 关闭指针压缩 : 16B = 8B + 8B + 0 + 0 + 0
public class CountEmptyObjectSize {
    public static void main(String[] args) {
        CountEmptyObjectSize obj = new CountEmptyObjectSize();
        System.out.println(ClassLayout.parseInstance(obj).toPrintable());
    }
}
普通对象
  • 开启指针压缩 : 24 = 8B + 4B + 0B + 4 * 2 + 4B
  • 关闭指针压缩 : 24 = 8 + 8 + 0 + 4*2 + 0
public class CountObjectSize {
    int a = 10;
    int b = 20;
    public static void main(String[] args) {
        CountObjectSize object = new CountObjectSize();
        System.out.println(ClassLayout.parseInstance(object).toPrintable());
    }
}
数组对象
  • 开启指针压缩 : 32B = 8 + 4 + 4 + 4 * 3 + 4B
  • 关闭指针压缩 : 40B = 8 + 8 + 4 + 4 + 4 * 3 + 4B (两段填充)
public class CountSimpleObjectSize {
    static int[] arr = {0, 1, 2};
    public static void main(String[] args) {
        CountSimpleObjectSize test1 = new CountSimpleObjectSize();
        System.out.printf(ClassLayout.parseInstance(arr).toPrintable());
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值