Java对象在内存中的存储

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位:

Java对象在内存中的存储_第1张图片

64位:

Java对象在内存中的存储_第2张图片

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


    org.openjdk.jol
    jol-core
    0.9

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)

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

Java对象在内存中的存储_第3张图片

 

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

结果二:(数组)

Java对象在内存中的存储_第4张图片

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

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

Java对象在内存中的存储_第5张图片

实例数据中, 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(轻量级锁)

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

你可能感兴趣的:(java,jvm,开发语言)