Object memory layout of JVM

In this article we will introduce the memory layout of objects & how to access objects in the heap.

foreword

Object object = new Object() Tell me about your understanding of this sentence? Generally speaking, according to the default situation of JDK8, how much memory space is occupied by a new object.

  • It has been discussed before that the location of the object is stored in the heap (conventional situation: Garden of Eden → S0/S1 → old generation)
  • Now let's talk about layout, that is, what is the composition of the object? Head and body?

image-20230128003114228.png

object memory layout

In the HotSpot virtual machine, the storage layout of objects in heap memory can be divided into three parts: object header (Header), instance data (Instance Data) and alignment padding (Padding)

1) Object header

The object header contains two parts of data:

  • Runtime arity Mark Word
  • Type pointer Class Pointer

If the object is an array, the length of the array also needs to be recorded. As shown below:

image-20230128003700443.png

Runtime Metadata Mark World

  • Store information such as HashCode, object age, lock status flag, lock held by thread, etc.

  • In a 64-bit system, the Mark Word occupies 81 byte, and the type pointer occupies 81 byte [ 4 bytes when pointer compression is enabled], a total of 16 (12) bytes;

  • If a new object has no instance data, it is 16 bytes [the default is to start pointer compression -XX:+UseCompressedClassPointers, alignment padding 4 bytes]

  • The storage structure of Mark Word is shown in the figure below

    image-20230128004733823.png

Type pointer Class Pointer

  • Pointing to the class meta information (object template) in the method area, the virtual machine uses this pointer to determine which class the object is an instance of

2) Instance data

  • It is the effective information actually stored by the object, that is, various types of attributes defined in the class (including inherited from the parent class and defined by itself).
  • Instance data storage has certain rules:
    1. Fields of the same width are always allocated together;
    2. Variables defined in the parent class will appear before the subclass;
    3. If the CompactFields parameter is true (default is true): the narrow variable of the subclass may be inserted into the gap of the parent class variable

3) Align padding

  • 虚拟机要求对象起始地址必须是8字节的整数倍【具体原因这里就不赘述了,读者可自行查阅相关资料】。
  • 填充数据不是必须存在的,仅仅是为了字节对齐这部分内存按8字节补充对齐

4)JOL验证

引入JOL依赖

<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.9</version>
</dependency>
复制代码

使用JOL查看Object对象内部细节

image-20230128011130683.png

使用JOL查看Customer对象内部细节

public class Customer {
    int id;
    boolean flag = false;
    public static void main(String[] args) {
        System.out.println(ClassLayout.parseInstance(new Customer()).toPrintable());
    }
}
复制代码

image-20230128011916396.png

  • 7→填充的字节数
  • 声明一个Customer的实例,只有一个对象头的实例对象,12字节(开启压缩指针)+ 4字节[int] + 1字节[boolean]=17字节,此时需要对齐填充到24字节

默认开启指针压缩的 -XX:+UseCompressedClassPointers

  • 12 + 4(对齐填充) == 一个对象16字节(不算实例数据)

手动关闭指针压缩 -XX:-UseCompressedClassPointers

  • 8 + 8 == 16字节(不算实例数据)

图示对象的内存布局

image-20230128012158496.png

对象的访问定位

创建对象是为了后续使用该对象,那么JVM是如何通过栈帧中的对象引用访问到其内部的对象实例的呢?

  • 通过栈上的reference访问

而reference类型只是一个指向对象的引用,并没有定义这个引用应该通过什么方式去定位、访问到堆中对象的具体位置,而JVM中主流的对象访问方式主要有使用句柄直接指针两种方式。

1)句柄访问

Java堆中可能会划分出一块内存来作为句柄池,而reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自具体的地址信息。

  • 优点:reference中存储稳定句柄地址,对象被移动(垃圾收集时候移动对象很普遍)时会改变句柄中的实例数据指针即可,reference本身不需要被修改
  • 缺点:需要多占用一些空间

image-20230128113610266.png

2)直接指针

  • HotSpot使用该方式。

If you use direct pointer access, the memory layout of the object in the Java heap must consider how to place the relevant information of the access type data. The object address is directly stored in the reference. If you only access the object itself, there is no need for an additional indirect access overhead. .

image-20230128114455925.png

Guess you like

Origin juejin.im/post/7193547233650802746