JVM 中 java 对象布局

HostSpot 虚拟机对象布局

1.java 对象布局

Java对象分为:对象头、实例数据、对齐填充组合。

对齐填充:

对齐填充并不是必然存在的,也没有特定的含义,仅仅起着占位符的作用。由于HotSpot虚拟机的自动内存管理系统要求对象的起始地址必须是8字节的整数倍,也就是对象的大小必须是8字节的整数倍。而对象头部分正好是8字节的倍数(1倍或者2倍),因此,当对象实例数据部分没有对齐的时候,就需要通过对齐填充来补全。对象字节数/8的倍数,如果不足的话 实现填充。例如:一个对象21个字节,则需要补充3个字节。

实例数据:对象中定义的成员属性。

对象头:

固定的大小。32位系统对象头大小为8个字节、64位系统对象头大小为16个字节。

HotSpot虚拟机的对象头(Object Header)包括两部分信息:

第一部分"Mark Word":用于存储对象自身的运行时数据, 如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等.

第二部分"Klass Pointer":对象指向它的类的元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。(数组,对象头中还必须有一块用于记录数组长度的数据,因为虚拟机可以通过普通Java对象的元数据信息确定Java对象的大小,但是从数组的元数据中无法确定数组的大小。 )

注意:在64位的虚拟机情况下 mark word 占用64位 ,32位虚拟机占32位。

64位等于多少 /8 8个字节

虚拟机源码中查看Mark Word:

 KClass Pointer:

这一部分用于存储对象的类型指针,该指针指向它的类元数据,jvm通过这个指针确定对象是哪个类的实例。该指针的位长度为JVM的一个字大小,即32位的JVM为32位,64位的JVM为64位。

如果应用的对象过多,使用64位的指针将浪费大量内存,统计而言,64的JVM将会比32位的JVM多耗费50的内存。为了节约内存可以使用选项 -XX:+UseCompressedOops 开启指针压缩。其中 oop即ordinary object pointer 普通对象指针。

如果在64位操作系统下,如果对象头字节为12个字节,说明是java虚拟机对对象头进行了压缩。

对象头压缩设置:

-XX:+UseCompressedOops 开启指针压缩

-XX:-UseCompressedOops  不开启指针压缩

对象头:Mark Word+Klass Pointer类型指针 未开启压缩的情况下

32位 Mark Word =4bytes ,类型指针 4bytes ,对象头=8bytes =64bits

64位 Mark Word =8bytes ,类型指针 8bytes ,对象头=16bytes=128bits;

注意:默认情况下,开启了指针压缩 可能只有12字节。

new出一个对象对象头占多少个字节:

如果是32位操作系统对象头占8个字节,如果是64位操作系统对象头占16个字节(没有被压缩的情况下)。

占用字节=对象头+实例数据+对齐填充/8

 

 

java 打印对象头信息所需Maven依赖:

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

 

java 代码实现:对象为 int 类型

public class UserEntity {

    private int a;

    public static void main(String[] args) {
        UserEntity userEntity = new UserEntity();
        // 打印对象头信息
        System.out.println(ClassLayout.parseInstance(userEntity).toPrintable());
    }
}

控制台打印结果:
com.example.test.UserEntity object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           80 30 d1 1b (10000000 00110000 11010001 00011011) (466694272)
     12     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
     16     4    int UserEntity.a                              0
     20     4        (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

java 代码实现:对象为 Interger 类型

public class UserEntity {

    private Integer a;

    public static void main(String[] args) {
        UserEntity userEntity = new UserEntity();
        // 打印对象头信息
        System.out.println(ClassLayout.parseInstance(userEntity).toPrintable());
    }
}

控制台打印结果:
com.example.test.UserEntity object internals:
 OFFSET  SIZE                TYPE DESCRIPTION                               VALUE
      0     4                     (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4                     (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4                     (object header)                           80 30 1c 1c (10000000 00110000 00011100 00011100) (471609472)
     12     4                     (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
     16     8   java.lang.Integer UserEntity.a                              null
Instance size: 24 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

 Integer包装类型会对int类型自动的进行填充,由4变成了8,能够被8整除。

 

 打印 对象hashcode位置:

public class UserEntity {

    private int a;

    public static void main(String[] args) {
        UserEntity userEntity = new UserEntity();
        // 打印 hashCode 所在位置
        System.out.println(Integer.toHexString(userEntity.hashCode()));
        // 打印对象头信息
        System.out.println(ClassLayout.parseInstance(userEntity).toPrintable());
    }
}

控制台输出:
5b2133b1
com.example.test.UserEntity object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 b1 33 21 (00000001 10110001 00110011 00100001) (557035777)
      4     4        (object header)                           5b 00 00 00 (01011011 00000000 00000000 00000000) (91)
      8     4        (object header)                           00 31 4f 1c (00000000 00110001 01001111 00011100) (474951936)
     12     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
     16     4    int UserEntity.a                              0
     20     4        (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

基本数据类型占多少字节

1、bit --位:位是计算机中存储数据的最小单位,指二进制数中的一个位数,其值为“0”或“1”。

2、byte --字节:字节是计算机存储容量的基本单位,一个字节由8位二进制数组成。在计算机内部,一个字节可以表示一个数据,也可以表示一个英文字母,两个字节可以表示一个汉字。

64位/8
1Byte=8bit  (1B=8bit) 
1KB=1024Byte(字节)=8*1024bit
1MB=1024KB
1GB=1024MB
1TB=1024GB
int        32bit  4  
short    16bit  2
long      64bit 8
byte      8bit
char      16bit
float      32bit
double   64bit
boolean 1bit

  

posted @ 2021-03-04 17:02  明天,你好啊  阅读(203)  评论(0编辑  收藏  举报