起笔
最近的一段时间的精神有点萎靡,导致前两篇文章写的不尽人意,所以就休息了一段时间再来更新文章。
参考书籍:“深入理解java虚拟机”
个人java知识分享项目gitee地址:Cornucopia
个人java知识分享项目github地址:Cornucopia
对象的内存布局
在HotSpot虚拟机中,对象的内存布局分为一下3块区域:
- 对象头(Header)
- 实例数据(Instance Data)
- 对齐填充(Padding)
对象头中包含了类型指针(Class Pointer),通过改指针能确定对象属于那个类。如果对象是数组对象那么对象头中还会包含数组的长度。
对象头(Header)
在HostSpot虚拟机对象的对象头部分包含了两类信息:
-
用于存储对象自身的运行时数据,如哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等,这部分数据的长度在32位和64位的虚拟机中分别为32bit和64bit(8byte),官方称它为“Mark World”
-
对象头的另外一部分是类型指针,即对象指向它的类型元数据的指针(Class Pointer),Java虚拟机通过这个指针来确定该对象是那个类的实例。此外,因为虚拟机可以通过普通Java对象的元数据信息确定Java对象的大小,但是如果数组的长度是不确定,将无法通过元数据的信息推断出数组的大小。因此,如果对象是一个数组,那么对象头中还必须有一块用于记录数组长度的数组,也就是上图中的Data Length。
实例数据(Instance Data)
实例数据是对象真正存储的有效信息,即我们在程序代码里面所定义的各种类型的字段内容,无论是从父类继承下来的,还是在子类中定义的字段都必须记录起来。
对齐填充(Padding)
对齐填充并不是必然存在的,也没有特别的含义,它仅仅起占位符的作用。那为什么要有这么一段数据是因为HotSpot虚拟机的自动内存管理系统要求对象起始地址必须是8byte的整数倍,换句话说就是任何对象的大小都必须是8字节的整数倍。对象头部分已经被精心设计成正好是8byte的倍数(1倍或者是2倍),因此,如果对象实例数据部分没有对齐的话,就需要通过对齐填充来补全。
分析案例
我们已经有对象内存布局的理论知识,现在,我们通过一个案例来加深一下印象:
案例:
new user();在内存中一共占多少个字节?
public class user {
private String name;
private int age;
}
解析
在开始之前,我们需要创建一个maven项目,然后引入JOL工具包
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.16</version>
</dependency>
执行代码:
public class ObjectTest {
public static void main(String[] args) {
System.out.println(ClassLayout.parseInstance(new user()).toPrintable());
}
static class user {
private String name;
private int age;
}
}
JVM参数:
打印被设置的参数 : -XX:+PrintCommandLineFlags
结果:
JVM参数打印:
-XX:InitialHeapSize=268435456 -XX:MaxHeapSize=4294967296 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
终端输出内容:
我们来分析一下,首先看jvm参数中的XX:+UseCompressedClassPointers ,我们知道它开启了指针压缩(也就是会压缩ClassPointer的内存大小,从8byte->4byte),那么,按照上面我们掌握的理论知识,一个对象内存包含三个部分,对象头为固定的8byte,ClassPointer如果开启了指针压缩则是4byte,Instance Data这里user中包含了一个int对象占4byte,String是一个引用对象固定占4byte,也就是Instance Data总共占8byte,由于Padding是占位符,我们先不分析,这里对象头和对象数据总共占 8+4+8=20,这里20不是8的倍数,由于jvm的内存管理的限制,这里jvm会将padding按找距离20byte最少的8的倍数进行填充,也就是24byte,padding就是4byte(即图中的 (object alignment gap) 所占的byte大小)。