关于java:对象在内存中的内存布局是什么样的

3次阅读

共计 2023 个字符,预计需要花费 6 分钟才能阅读完成。

一个 Java 对象的存储构造。在 Hotspot 虚拟机中,对象在内存中的存储布局分为 3 块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)

Java 对象实例

Hotspt 采纳了 OOP-Klass 模型。它是形容 java 对象实例的模型,可分为两局部:

OOP(Ordinary Object Pointer)指的是一般对象指针,它蕴含 MarkWord 和 Klass 指针。MarkWord 用于存储以后对象运行时的一些状态数据;Klass 指针则指向 Klass,用来通知以后指针指向的对象是什么类型,即对象是应用哪个类创立进去的
之所以采纳这种一分为二的对象模型,是因为 hotspot jvm 的设计者不想让每个对象中都蕴含一个 virtual table(虚函数表),所以把对象模型拆成 klass 和 oop,其中 oop 不蕴含任何虚函数,而 klass 含有虚函数表,能够进行 method dispatch

– 对象头

HotSpot 虚拟机的对象头包含两局部信息:

_mark:markOop
第一局部_mark:markOop, 用于存储对象本身的运行时数据,如哈希码(HashCode)、GC 分代年龄、锁状态标记、线程持有的锁、偏差线程 ID、偏差工夫戳等。这部分数据的长度在 32 位和 64 位的虚拟机(未开启压缩指针)中别离为 32bit 和 64bit,官网称“MarkWord”

_klass:klassOop
对象头的另外一部分是 klass 类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例

length
如果是数组对象的话,对象头还有一块示意数组长度的数据,大小是 32bit,4 个字节

– 对象理论数据

实例数据局部是对象真正存储的无效信息,也是在程序代码中所定义的各种类型的字段内容。无论是从父类继承下来的,还是在子类中定义的,都须要记录起来。

对齐填充

第三局部对齐填充并不是必然存在的,也没有特地的含意,它仅仅起着占位符的作用。因为 HotSpot VM 的主动内存管理系统要求对象起始地址必须是 8 字节的整数倍,换句话说,就是对象的大小必须是 8 字节的整数倍。而对象头局部正好是 8 字节的倍数(1 倍或者 2 倍),因而,当对象实例数据局部没有对齐时,就须要通过对齐填充来补全。

简略能够概括如下

晓得了这 4 个局部之后,咱们来验证一下底层。借助于第三方包 JOL = Java Object Layout java 内存布局去看看。很简略的几行代码就能够看到内存布局的款式:

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

public class JOLSampleDataModels {
 
    private static Object o;
 
    public static void main(String[] args) {o = new Object();
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
        System.out.println("================== 加载锁之后 ==================");
        synchronized (o) {System.out.println(ClassLayout.parseInstance(o).toPrintable());
        }
    }
}

从输入后果看:

对象头蕴含了 12 个字节分为 3 行,其中前 2 行其实就是 markword,第三行就是 klass 指针。值得注意的是在加锁前后输入从 001 变成了 000。Markword 用途:8 字节 (64bit) 的头记录一些信息,锁就是批改了 markword 的内容 8 字节 (64bit) 的头记录一些信息,锁就是批改了 markword 的内容字节 (64bit) 的头记录一些信息。从 001 无锁状态,变成了 00 轻量级锁状态。

New 出一个 object 对象,占用 16 个字节。对象头占用 12 字节,因为 Object 中没有额定的变量,所以 instance = 0,思考要对象内存大小要被 8 字节整除,那么 padding=4,最初 new Object() 内存大小为 16 字节。

拓展

什么样的对象会进入老年代?很多场景例如对象太大了能够间接进入,然而这里想探讨的是为什么从 Young GC 的对象最多经验 15 次 Young GC 还存活就会进入 Old 区(年龄是能够调的,默认是 15)。上图中 hotspots 的 markword 的图中,用了 4 个 bit 去示意分代年龄,那么能示意的最大范畴就是 0 -15。所以这也就是为什么设置新生代的年龄不能超过 15,工作中能够通过 -XX:MaxTenuringThreshold 去调整,然而个别咱们不会动。

【欢送关注】:码农架构

专一于零碎架构、高可用、高性能、高并发类技术分享

正文完
 0