这是我参与8月更文挑战的第8天,活动详情查看:8月更文挑战
JOL简介
JOL(Java对象布局)是用于分析JVM中对象布局方案的微型工具箱。这些工具大量使用Unsafe、JVMTI和可服务性代理(SA)来解码实际的对象布局、示意图和引用。
jol的官方文档openjdk.java.net/projects/co…
本文着重介绍怎么使用JOL查看对象的结构,关于对象的结构文章,可以参考juejin.cn/post/699330…
对象头的结构信息
使用JOL工具查看java对象布局
引入jol依赖
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.16</version>
</dependency>
创建对象示例
Foo类中有一个整形变量i,一个长整形变量j和一个引用类型变量bar
- Bar
public class Bar {
private int k;
}
- Foo
public class Foo {
private int i;
private long j;
private Bar bar;
}
打印对象信息
打印没有HashCode的对象信息
@Test
public void test() {
Foo foo = new Foo();
System.out.println(ClassLayout.parseInstance(foo).toPrintable());
}
输出结果:
org.ywb.Foo object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 4 (object header: class) 0xf8011ce4
12 4 int Foo.i 0
16 8 long Foo.j 0
24 4 org.ywb.Bar Foo.bar null
28 4 (object alignment gap)
Instance size: 32 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
-
出对象头包含两部分,
MarkWord和ClassPoint分别占用了8个字节和4个字节,因为没有任何同步代码块使用该对象作为锁,所以该对象处于一个无锁状态,即,偏向锁的标志位为0,锁标志位01。 -
对象体此时有三个属性,分别是占用4个字节的int类型的i,占用8个字节的long类型变量j,和一个引用类型,长度为4。
java 数据类型所占字节数
-
因为JVM规定,对象头的大小必须是8字节的整数倍,因为 8 + 4 = 12,不够,所以需要额外的 4字节
object alignment gap(对齐字节)进行填充。 -
对象初始化后,会自动调用
<init>方法对对象属性进行赋值,int,long类型默认复制为0,引用类型默认赋值为null -
对象总大小为32字节
打印带hashCode的对象结构信息
对象一旦生成了 hashcode,JVM 会将其记录在对象头的 Mark Word 中;
注意只有调用未重写的 Object.hashcode()方法,或者调用 System.IdentityHashCode(obj)方法时,其值才被记录到 Mark Word中;如果调用的是重新的 hashcode()方法,也不会记录到 Mark Word 中。
对象一旦生成了 hashcode,那么它就无法进入偏向锁状态;也就是说,只要一个对象已经计算过 hashcode,它就无法进入偏向锁状态;当一个对象当前正处于偏向锁状态,并且需要计算其 hashcode 的话,则它的偏向锁会被撤销,并且锁会膨胀为重量级锁。
@Test
public void test() {
Foo foo = new Foo();
int code = foo.hashCode();
System.out.println(ClassLayout.parseInstance(foo).toPrintable());
}
输出结果:
org.ywb.Foo object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x000000694f943101 (hash: 0x694f9431; age: 0)
8 4 (object header: class) 0xf8011d21
12 4 int Foo.i 0
16 8 long Foo.j 0
24 4 org.ywb.Bar Foo.bar null
28 4 (object alignment gap)
Instance size: 32 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
跟刚刚的没有太大区别,只是对象HashCode被存储在对象头中了。
数组对象结构信息
@Test
public void test() {
Foo[] foos = new Foo[4];
System.out.println(ClassLayout.parseInstance(foos).toPrintable());
}
输出结果:
[Lorg.ywb.Foo; object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 4 (object header: class) 0xf8011d23
12 4 (array length) 4
12 4 (alignment/padding gap)
16 16 org.ywb.Foo Foo;.<elements> N/A
Instance size: 32 bytes
Space losses: 4 bytes internal + 0 bytes external = 4 bytes total
- 对象头中增加了一个数组长度的属性,这个属性在一般对象中是没有的,只有类型为数组类型才具备。
- 对象体中只有一个属性,因为我们的数组申请的长度为4,一个引用的大小为4,所以该属性的大小为 4 * 4 = 16