如何查看Java对象布局我们需要引入一个工具
org.openjdk.jol jol-core0.16
这个是openjdk的查看对象布局的一个库
上使用代码
public static void main(String[] args) {
Object obj = new Object();
System.out.printf(ClassLayout.parseInstance(obj).toPrintable());
}
打印结果如下
java.lang.Object object internals: OFF SZ TYPE DESCRIPTION VALUE 0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0) 8 4 (object header: class) 0x00000d08 12 4 (object alignment gap) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
从上面打印上可以看出一个Object对象是占用16个字节的,其中12个字节为对象头
按照上面这张图我们新建一个有成员变量的对象再次打印内存布局进行验证
类代码如下
public class Main {
private int i;
private long ll;
public static void main(String[] args) {
Main obj = new Main();
System.out.printf(ClassLayout.parseInstance(obj).toPrintable());
}
}
打印结果
org.example.Main object internals: OFF SZ TYPE DESCRIPTION VALUE 0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0) 8 4 (object header: class) 0x00c03800 12 4 int Main.i 0 16 8 long Main.ll 0 Instance size: 24 bytes Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
从上面代码可以看出Main.class有两个成员变量分别是int类型(4字节)和long类型(8字节)
markword+class pointet+instance data = 8+4+4(int)+8(long) = 24的出Main对象是24个字节可以验证上面图是正确的由于24刚好能被8整除所以不需要增加padding填充字节.
接下来我们使用synchronized加下锁看下打印会不会有改变
public static void main(String[] args) {
Main obj = new Main();
System.out.printf(ClassLayout.parseInstance(obj).toPrintable());
synchronized (obj){
System.out.printf(ClassLayout.parseInstance(obj).toPrintable());
}
}
org.example.Main object internals: OFF SZ TYPE DESCRIPTION VALUE 0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0) 8 4 (object header: class) 0x00c03800 12 4 (object alignment gap) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total org.example.Main object internals: OFF SZ TYPE DESCRIPTION VALUE 0 8 (object header: mark) 0x00000047b75ff040 (thin lock: 0x00000047b75ff040) 8 4 (object header: class) 0x00c03800 12 4 (object alignment gap) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
在使用synchronized锁定对象后可以发现markword的值是被改变并且小括号内携带锁信息(thin lock: 0x00000047b75ff040).
接下来我们在调用一下obj.hashCode看下打印是怎样的
org.example.Main object internals: OFF SZ TYPE DESCRIPTION VALUE 0 8 (object header: mark) 0x00000066d1af8901 (hash: 0x66d1af89; age: 0) 8 4 (object header: class) 0x00c03800 12 4 (object alignment gap) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
从上面打印看到了hash: 0x66d1af89说明hashCode也是存储在markword中,并且还看到了一个age属性.我们实验一下调用system.gc再次看看打印
org.example.Main object internals: OFF SZ TYPE DESCRIPTION VALUE 0 8 (object header: mark) 0x00000016b98e5601 (hash: 0x16b98e56; age: 1) 8 4 (object header: class) 0x00c03800 12 4 (object alignment gap) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
可以看到age变化了说明分代年龄也存放在markword中
markword中存储hashCode,分代年龄,锁信息



