2、JAVA堆中的对象

xiaoxiao2021-02-28  90

堆中的对象

堆是垃圾GC的主要区域。那么堆中对象实例就有必要进行了解一下了。

一、对象的创建

Java是面向对象语言,所以在Java程序运行的时候每时每刻都会有对象创建。而编写代码的时候,创建对象仅仅是通过关键字new来实现的。

即虚拟机遇到一条new指令后,会先去检查相应的类是否被加载、解析和初始化过,没有的话就加载相应的类来创建出这个对象来。这个过程实际上会更复杂一些。首先虚拟机会先检查类加载,通过加载后就会为即将创建的对象分配内存。而如果可分配的内存不是完整的一段内存的话,还需要维护一个列表来记录哪些内存块是可用的,然后再取出一块足够大的空间划分给对象实例,并更新记录列表。

分配完内存后还需要对分配到的空间进行初始化,包括一些必要的设置。并把设置完的一些信息存放到对象头(Object Header)中。而到这里后,对于虚拟机来说,对象已经产生了,但是对于程序来说,对象的创建才仅仅只是开始而已。这个时候还会执行一个init方法,把对象按照我们的意愿进行初始化后,才是真正的一个对象完整的创建出来。

二、对象的内存布局

上面有提到了对象头是用来存放一个对象的必要信息的。其实,对象在内存中的存储区域可分为3块:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。

对象头:对象头分为两部分,一部分是存储对象自身的运行时数据(HashCode、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等),另一部分则是类型指针,即对象指向它的类元数据的指针,虚拟机可以通过这个指针确定这个对象是哪个类的实例。当然查找对象的元数据信息也不一定是要经过对象本身的类型指针的。实例数据:对象真正存储数据的有效部分。对齐填充:仅仅起到了占位符的作用。因为对象的大小必须是8字节的整数倍。因为对象头正好是8字节的倍数,而对象实例数据部分就不一定了,所以需要通过对象填充来不全。

三、对象的访问定位

Java程序是通过栈上的reference数据来操作堆上的具体对象的。由于在Java虚拟机规范中红只规定了一个指向对象的引用,没有定义这个引用应该通过什么方式去定位和访问对象的具体位置,所以对象的访问方式就取决于虚拟机实现而定了。目前主流的访问方式有使用句柄和直接指针两种。

1、句柄访问

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

2、直接指针访问

Java堆对象的布局就需要考虑如何防止访问类型数据的相关信息了,而reference中存储的就是对象地址。

句柄范根的好处在于reference中存储的是稳定的句柄地址,在对象被移动时只会改变句柄的实例数据指针,reference本身不会修改。 直接指针访问的好处在于速度更快,节省一次指针定位的时间开销,对于需要频繁访问对象的Java来说,这个时间开销的节省累积起来还是很可观的。

转载请注明原文地址: https://www.6miu.com/read-47168.html

最新回复(0)