在Java中通过new关键字创建对象时,会根据堆是否规整的特点(受垃圾收集器的影响) ,以不同的方式分配指定大小的内存空间给新对象使用。这一部分内存空间会会划分为"对象头"、"实例数据"、"对齐填充"三部分。当对象初始化完毕之后,为了能够让外部正常使用,一般会选择"直接指针"或是"句柄"的方式提供对外访问的能力。
1. 内存分配策略
在通过new关键字创建新的对象时,虚拟机会先定位类符号引用,且执行类加载过程(若类已经被加载了过则该步骤跳过,详细信息需见第七章)。此后,便需要给新生对象分配其可用内存,这一块内存区域是在堆上的。
堆是垃圾收集器的工作空间。在执行垃圾收集操作之后,未被回收的对象不规则的分配在堆内,产生大量的碎片空间,如下:
这样的堆内存被称为是"不规整"的,需要通过"空闲列表(Free List) "的方式记录哪些内存是可用的,其大小是多少,从够分配给不同大小的对象所使用。
有一些垃圾收集器具备"整理"的能力,会在清理掉"死亡"对象之后,将存活对象集中在一起存储,从而产生"规整"的堆内存。
此时,在已使用内存和未使用内存之间存在鲜明的一条分界线,称为"临界点"。在给新对象分配内存时,只需要将临界点向空闲内存方向平移一定的距离即可,这种分配内存的方式被称为"指针碰撞(Bump The Pointer) "。
当然,创建对象的行为很有可能是并发执行的,虚拟机提供了两种方式来解决并发分配内存的问题:
CAS+ 失败重试;- 在上一篇文章中,提到了
Thread Local Allocation Buffer, TLAB,可以通过-XX: +/-UseTLAB开启或关闭。这项机制会给每一个线程在堆上预分配一块内存区域,称为"本地缓冲区",当缓冲区使用完毕之后,会使用同步或CAS的方式分配新的缓冲区。在使用缓冲区内的内存空间时,不需要考虑并发的问题。
2. 对象内存布局
分配给新生对象的内存会被划分为"对象头"、"实例数据"和"对齐填充"3个部分。
2.1 对象头
对象头包含了两部分信息:一部分是对象自身的运行时数据,包括哈希码、分代信息、锁标志等等,被称为Mark Word 。另一部分是类型指针。
2.1.1 Mark Word
在32位虚拟机和64位虚拟机中,这部分数据的长度分别为32比特和64比特(未开启压缩)。由于对象运行时数据很多,远远超过了32比特或64比特的长度,因此Mark Word被设计为具有动态定义的数据结构。以32位虚拟机为例,其结构如下:
2.1.2 类型指针
这一部分是对象指向其类型元数据的指针。不过,查找对象的类型元数据不一定需要通过对象本身(见本文"句柄"部分),因此不是所有的虚拟机都在对象头中有存储类型指针。
2.1.3 补充:数组长度
如果对象是数组的情况下,对象头中还必须留有一块区域用于存储数组的长度,从而使得虚拟机能够识别出对象的大小。
2.2 实例数据
这一部分存储对象所有字段的信息,包括继承的和自身所定义的。字段的存储顺序受虚拟机分配策略参数--XX:FieldsAllocationStyle和源码中字段的定义顺序所影响。HotSpot 虚拟机的默认字段分配顺序为:
double/long;int;short/char;byte/boolean;Ordinary Object Pointers;
如果+XX:CompactFields参数为true(默认值就为true),则子类中较窄的变量也允许插入到父类变量的空隙中,以节省空间。
2.3 对齐填充
HotSpot虚拟机要求对象的起始地址必须是8字节的整数倍,因此任何对象的大小都必须是8字节的整数倍,不满足这个条件的对象会使用"对齐填充"区域来进行填充。
3. 对象访问方式
在《Java虚拟机规范》中,只定义了reference类型是一个指向对象的引用,并没有规定reference类型的具体访问和定位对象的方式,因此在主流的虚拟机中,会存在"直接指针"和"句柄"两种方式来完成此项工作。
3.1 直接指针
指reference直接存储的对象的地址。这种方式必须要求对象头中具备"类型指针"的信息,从而使得引用、对象和类型三者能够关联起来。
直接指针的特点是高效,只需要一次定位就能够访问到对象的具体信息。HotSpot虚拟机也是使用的"直接指针"。
3.2 句柄
在堆内存中划分一块区域作为"句柄池",池中存储的数据单元也就是"句柄"。
句柄中包含了对象本身和其类型数据各自的地址信息,而reference存储的是句柄自己的地址。可以看出,使用句柄的方式去访问对象,需要执行两次定位操作,效率较低。不过使用句柄的情况下,对象头中就可以不包含"类型指针"的信息了。此外,在使用具备"整理"功能的垃圾收集器执行完回收操作之后,对象的地址往往会发生变化,此时只需要修改句柄内访问对象实例的指针地址,而不再需要去修改reference 本身,这也是句柄的优势。