JAVA内存区域 --(2)对象创建

2018-10-10  本文已影响0人  黑色偏幽默

JAVA内存区域 --(2)对象创建

JVM 在遇到一条 new 指令时,是如何为其分配内存空间并初始化的呢?
笔者将流程画成了一个简单的流程图:

创建对象的流程.png

这里我们先略过第二步的类加载机制,主要讲述后面 4 个步骤。

分配内存

确认内存位置

分配对象的过程中,需要为对象划分足够大的内存空间,而如何从 Java 堆中找到合适大小的空间,通常用以下两种方法:

而以上两种方法由虚拟机的 Java 堆是否规整决定,也就是由 GC 算法是否具备压缩整理的能力决定。

确保线程安全

多个线程在创建对象时,为了保证分配内存空间的动作是同步处理的:

对象的内存分布

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

对象头(Header)

对象头包含两部分的信息:

如果对象是一个 Java 数组,那在对象头中还需要一块用于记录数组长度的数据。

实例数据(Instance Data)

实例数据部分是对象真正有效的信息,也就是在程序中定义的各种类型的字段内容。
这个存储顺序还会受到虚拟机的分配策略参数和字段在 Java 源码中定义顺序影响。HotSpot 默认的分配策略为 longs / doubles、ints、shouts / chars、bytes / booleans、oops(Ordinary Object Pointers),即把相同大小的字段分配到一起。

对齐填充(Padding)

对齐填充并不是必须存在的,也没有特别含义,仅仅起到占位符的作用。因为 HotSpot 的自动内存管理系统要求对象的起址位置必须是8字节的整数倍。

对象的访问定位

我们通过栈上的 reference 数据来操作堆上的具体对象。目前通过主流的方式 句柄直接指针 去定位、访问堆中对象的具体位置。

句柄:Java 堆中将划出一块内存作为句柄池,reference 中存储的就是对象的句柄地址,而句柄中包含了对象的实例数据地址和类型数据的地址。

使用句柄访问

直接指针访问:在 Java 堆中对象放置了访问类型数据的相关地址,而 reference 直接指向对象实例数据。

直接访问
上一篇下一篇

猜你喜欢

热点阅读