Java对象在内存中的存储

本文详细解读了Java HotSpot虚拟机中对象在内存中的3个区域划分,包括对象头、MarkWord和实例数据,以及针对不同场景(如无锁状态、数组和普通类实例)的实例演示。此外,讲解了锁标志位如何影响对象状态。
摘要由CSDN通过智能技术生成

1.HotSpot中,对象在内存中分为3块区域:

  • 对象头
  1. MarkWord(存储hashCode,gc分代年龄,锁标志,线程id等)
  2. KlassPointer (class相当于是对klass做了个镜像,方便我们访问)
  3. 数组长度(如果是数组才有, 固定占4字节,此处也可看出数组长度length的最大值为 2147483647 ,即二进制31个1)
  • 实例数据(成员变量等)
  • 对齐填充(保证对象是8个字节的整倍数)

补充说明KlassPointer : 例如我们执行main方法,类加载器会将主类加载到JVM,经历 加载-》验证-》准备-》解析-》初始化的过程,其中加载这一步,会去生成 Class对象作为方法区中,这个类的各种数据的访问入口。(类元信息放方法区,class是堆中的)而jvm实际是通过方法区的klass得到这个类的信息。

32位:

32位系统中每个位的表示,64位系统类似

64位:

在这里插入图片描述

 2.通过一个demo了解这三块区域
引入依赖

<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.9</version>
</dependency>

public class JOLSample {

    public static void main(String[] args) {
        ClassLayout layout = ClassLayout.parseInstance(new Object());
        System.out.println(layout.toPrintable());

        System.out.println();
        ClassLayout layout1 = ClassLayout.parseInstance(new int[]{});
        System.out.println(layout1.toPrintable());

        System.out.println();
        ClassLayout layout2 = ClassLayout.parseInstance(new A());
        System.out.println(layout2.toPrintable());
    }

    // -XX:+UseCompressedOops           默认开启的压缩所有指针
    // -XX:+UseCompressedClassPointers  默认开启的压缩对象头里的类型指针Klass Pointer
    // Oops : Ordinary Object Pointers
    public static class A {
        //8byte mark word
        //4byte Klass Pointer   如果关闭压缩-XX:-UseCompressedClassPointers或-XX:-UseCompressedOops,则占用8byte
        int id;        //4byte
        String name;   //4byte  如果关闭压缩-XX:-UseCompressedOops,则占用8byte
        byte b;        //1byte
        Object o;      //4byte  如果关闭压缩-XX:-UseCompressedOops,则占用8byte
    }
}


结果说明
OFFSET:偏移量 (不关注)
SIZE:占用的字节
TYPE:类型
DESCRIPTION:前半部分为十六进制,后半部分为二进制(括号部分)
window和linux默认为小端模式(更适合计算机底层原理,即从低位读取)
00001010 00001011 00001111 10000000 //工具打印出来的
10000000 00001111 00001011 00001010 //实际上计算机中为反过来,此时锁为重量级锁
Instance size: 总共占用的字节数
MarkWord用红框表示,klass指针用橙框,数组长度用灰框。

实例数据用黄框,对齐填充用淡蓝框

成员变量中的类大多都是占用4bit(指针压缩后4bit,未压缩8bit)

结果一:(没有成员变量的)

在这里插入图片描述

 

红色部分描述不严谨,实际为对象头的MarkWord部分

结果二:(数组)

在这里插入图片描述

int [I.element 部分为数组中的数据,demo中为空,所以占0字节,索引每多1个,多加4字节(加多少具体看类型,int为4)

结果三:(创建的普通类)

在这里插入图片描述

实例数据中, int占4byte;String占4byte(字符串是存储在常量池,所以此处占用的是name的引用指向池的‘地址’); byte和bool占1byte;long占8byte…

3.通过一个demo了解锁标志位

Object o = new Object();
System.out.println(ClassLayout.parseInstance(o).toPrintable());
synchronized (o){
    System.out.println(ClassLayout.parseInstance(o).toPrintable());
}


结果一:
00000001 00000000 00000000 00000000 (无锁状态)
结果二:
01101000 11110001 11110101 00000000(轻量级锁)

对应最上面的锁标志位可知,结果一为【无锁状态】,结果二为【轻量级锁】
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值