概念说明
Hotspot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头(Header)、实例数据 (Instance Data)和对齐填充(Padding)。
-
- 对象头:比如 hash码,对象所属的年代,对象锁,锁状态标志,偏向锁(线程)ID,偏向时间,数组长度(数组对象才有)等。
- 实例数据:存放类的属性数据信息,包括父类的属性信息;
- 对齐填充:由于虚拟机要求 对象起始地址必须是8字节的整数倍。填充数据不是必须存在的,仅仅是为了字节对齐。
内存布局图示:
对象头详解
HotSpot虚拟机的对象头包括:
1.Mark Word
用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。
这部分数据的长度在32位和64位的虚拟机中分别为32bit和64bit,官方称它为“Mark Word”。(要知道1字节为8bit,故非8字节即4字节。)
2.Klass Pointer(它的类元数据的指针)
对象头的另外一部分是klass类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。
32位4字节,64位开启指针压缩或最大堆内存<32g时4字节,否则8字节。(故非8字节即4字节。)
jdk1.8默认开启指针压缩后为4字节,当在JVM参数中关闭指针压缩(-XX:-UseCompressedOops)后,长度为8字节。
3.数组长度(只有数组对象有)
如果对象是一个数组, 那在对象头中还必须有一块数据用于记录数组长度。 4字节。非数组对象则是0。
使用JOL工具查看内存布局(验证理论步骤)
JOL工具说明
查看普通java对象的内部布局工具JOL(JAVA OBJECT LAYOUT),使用此工具可以查看new出来的一个java对象的内部布局,以及一个普通的java对象占用多少字节。
引入maven依赖(在pom.xml文件处添加)
代码语言:javascript复制<!-- 查看Java 对象布局、大小工具 -->
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.9</version>
</dependency>
使用方法
代码语言:javascript复制//查看对象内部信息
System.out.println(ClassLayout.parseInstance(obj).toPrintable());
测试
案例代码
代码语言:javascript复制public class ObjectJolTest {
public static void main(String[] args) {
Object obj = new TestObject1();
System.out.println(ClassLayout.parseInstance(obj).toPrintable());
Object obj2 = new TestObject2();
System.out.println(ClassLayout.parseInstance(obj2).toPrintable());
}
}
class TestObject1{}
class TestObject2{
private boolean flag;
private long p;
}
案例分析
1. 针对TestObject1类产生的对象,利用jol查看64位系统java对象(空对象),默认开启指针压缩,总大小显示16字节,前12字节为对象
额外拓展说明:
-
-
-
- OFFSET:偏移地址,单位字节;
- SIZE:占用的内存大小,单位为字节;
- TYPE DESCRIPTION:类型描述,其中object header为对象头;
- VALUE:对应内存中当前存储的值,二进制32位;
-
-
2. 针对TestObject2类产生的对象,利用jol查看64位系统java对象(非空对象),默认开启指针压缩,总大小显示24字节,前12字节为对象
3. 关闭指针压缩后:-XX:-UseCompressedOops(元数据指针的压缩没了,恢复为8字节,进而导致有可能需要填充的变为不需要填充,或者需要填充更多)
验证问题:例子中的对象占多少个字节?
对象代码展示
代码语言:javascript复制class TestObject3{
private int[] a = new int[6];
private String[] b;
private boolean flag;
}
对象分析
以之前分析可得,在开启压缩条件下,该对象为非数组对象,所以 Mark Word为8字节 Klass Pointer(元数据指针)为4字节 数组长度0字节。
可得对象头为12字节,然后实例数据:布尔值1字节 int数组对象4字节 String数组对象4字节,故实例数据9字节。
合计21字节,再依据对象字节数要为8的整数倍,所以应为24字节,填充3字节
分析验证
针对数组对象的分析
代码展示
代码语言:javascript复制public class ObjectJolTest {
public static void main(String[] args) {
Object obj4 = new int[7];
System.out.println(ClassLayout.parseInstance(obj4).toPrintable());
}
}
对象分析