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