JOL:( Java Object Layout),new 一个 Object 对象,看这个对象的内存布局?平时我们new一个对象出来,在堆里申请一块内存,那么这块内存的布局到底是什么样的呢?
这块内存的布局分为4个部分:
第一部分:markwork
第二部分:classpointer
第三部分:instanceData
第四部分:padding
前两部分称为Object header 对象头,其中第二部分classpointer为类指针,表明这个对象所属哪个类,比如对象Object,那么它的所属类就是Object.class,第三部分instanceData为实例数据,用来装成员变量,第四部分padding为补齐,一个对象的字节数必须能被8整除,不能整除的加padding对齐。
我们引入org.openjdk.jol
包,用Java程序打印下它的内存结构
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.9</version>
</dependency>
public static void main(String[] args) {
Object o = new Object();
System.out.println(ClassLayout.parseInstance(o).toPrintable());
}
# WARNING: Unable to attach Serviceability Agent. You can try again with escalated privileges. Two options: a) use -Djol.tryWithSudo=true to try with sudo; b) echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
java.lang.Object 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) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
Process finished with exit code 0
OFFSET表示从多少个字节开始,SIZE表示到OFFSET后的第几位,那么来看数据中的第一行:
从第0个字节开始,往后数4个字节,再看第二行:
从第4个字节开始,往后数4个字节,这两部分构成我们图中的markword,一共8个字节。再看第三行:
从第8个字节开始,往后数4个字节,这部分是我们图中的classpointer,指向Object.class这个类。再看第四行:
从第12个字节开始,往后数4个字节,loss due to the next object alignment
对象的对齐被丢掉了,什么意思?我们前面一共是3x4=12个字节,12不能被8整除,所以加了4个字节能够被8整除,所以最后的这4个字节是用来对齐用的。
MarkWord是干嘛用的?
有三个作用:
- 记录锁信息
记录GC记录HashCode (identity HashCode)
后两个不是我们讨论的内容,主要说第一个,记录锁信息,那这个markword到底怎么记录的呢?
我们在这个对象加把锁,再看下它的内存布局,和之前的对比下
public static void main(String[] args) {
Object o = new Object();
System.out.println(ClassLayout.parseInstance(o).toPrintable());
synchronized (Jol.class) {
System.out.println(ClassLayout.parseInstance(o).toPrintable());
}
}
java.lang.Object 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) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 90 c9 37 0e (10010000 11001001 00110111 00001110) (238537104)
4 4 (object header) 00 70 00 00 (00000000 01110000 00000000 00000000) (28672)
8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
看到了吗,加了锁的对象和不加锁的对象前两行VALUE值是不一样的,也就是markword是不一样的,所以说,给对象加锁就是修改了markword的值。
markword里面的内容都代表什么意思?来参考一张图
这是new Object() markword里面最低位值的参考
你可能有疑问,不是看最低位字节吗,不应该是最后面吗,怎么看最前面的?Little-Endian字节序,低位字节排在最前,只有网络传输的时候才是Big-Endian高位字节在前。