Java对象介绍

Posted by Kaka Blog on December 31, 2020

对象的内存布局

HotSpot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。

在java中对象的内存布局分为两种情况,非数组对象和数组对象,数组对象和非数组对象的区别就是需要额外的空间存储数组的长度length。

对象头

对象头又分为MarkWord和Class Pointer两部分。

  • MarkWord:包含一系列的标记位,比如轻量级锁的标记位,偏向锁标记位,gc记录信息等等,在32位系统占4字节,在64位系统中占8字节
  • ClassPointer:用来指向对象对应的Class对象(其对应的元数据对象)的内存地址。在32位系统占4字节,在64位系统中占8字节
  • Length:只在数组对象中存在,用来记录数组的长度,占用4字节

Instance data

Instance data:对象实际数据,对象实际数据包括了对象的所有成员变量,其大小由各个成员变量的大小决定。(这里不包括静态成员变量,因为其是在方法区维护的)

Padding

Padding:Java对象占用空间是8字节对齐的,即所有Java对象占用bytes数必须是8的倍数,是因为当我们从磁盘中取一个数据时,不会说我想取一个字节就是一个字节,都是按照一块儿一块儿来取的,这一块大小是8个字节,所以为了完整,padding的作用就是补充字节,保证对象是8字节的整数倍。

指针压缩

-XX:+UseCompressedOops可以压缩指针,将占用的空间压缩为原来的一半,起到节约空间的作用,classpointer参数大小就受到其影响。

Object o = new Object()到底占用多少个字节?

  • 在开启指针压缩的情况下,markword占用8字节,classpoint占用4字节,Instance data无数据,总共是12字节,由于对象需要为8的整数倍,Padding会补充4个字节,总共占用16字节的存储空间。
  • 在没有指针的情况下,markword占用8字节,classpoint占用8字节,Instance data无数据,总共是16字节。

OpenJDK,提供了JOL包,可以帮我们在运行时计算某个对象的大小。

添加依赖:

<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.14</version>
</dependency>

查看对象的内部信息:

public static void main(String[] args) {
    System.out.println(ClassLayout.parseInstance(new App()).toPrintable());
}

输出:

com.fang.App 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)                           05 c1 00 f8 (00000101 11000001 00000000 11111000) (-134168315)
     12     4    int App.a                                     0
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

分析:

JVM中,每个对象都有一个对象头,由标记字段和类型指针构成,标记字段存储hashCode, GC信息,锁信息,类型指针指向该对象的类。

  • Mark Word(标记字段):对象的Mark Word部分占8个字节(64位虚拟机),其内容是一系列的标记位,比如轻量级锁的标记位,偏向锁标记位等等。
  • Class Pointer(Class对象指针):Class对象指针的大小也是4个字节,其指向的位置是对象对应的Class对象(其对应的元数据对象)的内存地址
  • 对象实际数据:这里面包括了对象的所有成员变量,其大小由各个成员变量的大小决定,比如:byte和boolean是1个字节,short和char是2个字节,int和float是4个字节,long和double是8个字节,reference是4个字节
  • 对齐:最后一部分是对齐填充的字节,按8个字节填充。

参考