大厂面试(二)请描述new Object()的内存布局—美团

JOL:( Java Object Layout),new 一个 Object 对象,看这个对象的内存布局?平时我们new一个对象出来,在堆里申请一块内存,那么这块内存的布局到底是什么样的呢?

这块内存的布局分为4个部分:

第一部分:markwork

第二部分:classpointer

第三部分:instanceData

第四部分:padding

前两部分称为Object header 对象头,其中第二部分classpointer为类指针,表明这个对象所属哪个类,比如对象Object,那么它的所属类就是Object.class,第三部分instanceData为实例数据,用来装成员变量,第四部分padding为补齐,一个对象的字节数必须能被8整除,不能整除的加padding对齐。

大厂面试(二)请描述new Object()的内存布局—美团_第1张图片

我们引入org.openjdk.jol包,用Java程序打印下它的内存结构

<dependency>
    <groupId>org.openjdk.jolgroupId>
    <artifactId>jol-coreartifactId>
    <version>0.9version>
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是干嘛用的?

有三个作用:

  1. 记录锁信息
  2. 记录GC
  3. 记录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()的内存布局—美团_第2张图片

这是new Object() markword里面最低位值的参考

大厂面试(二)请描述new Object()的内存布局—美团_第3张图片

你可能有疑问,不是看最低位字节吗,不应该是最后面吗,怎么看最前面的?Little-Endian字节序,低位字节排在最前,只有网络传输的时候才是Big-Endian高位字节在前。

你可能感兴趣的:(面试)