JVM——对象的创建(3)

1. 对象的创建

我们先来看看对象的创造过程,如下图

对象的创建需要类的加载,这个以后会在类加载器的章节详细说明

我们先来讲讲虚拟机为对象分配内存

分配内存分为指针碰撞和空闲列表两种方式,这两种方式是由内存是否规整决定的,而是否规整又是由垃圾回收策略决定的,如果垃圾回收器有压缩整理的功能,则可以使用指针碰撞:

1)指针碰撞:前提是堆内存中的空闲空间十分的规整,使用和未使用的空间全部为连续,只需移动一下指针就可以了。

2)空闲列表:针对堆内存中空间零散的存在,虚拟机维护着一个列表,记录着哪里被分配了,哪里还空闲。

分配内存还要保证并发安全,也有两种方式:

3)CAS命令的方式来控制操作是同步的

4)TLAB(Thread Local Allocation BUffer    本地线程分配缓冲):在堆中为每一个线程分配一小块独立的内存,这样以来就不存在并发问题了,java层面与之对应的是ThreadLocal类的实现

2. 对象的结构

对象结构分为三部分:header(对象头)InstanceData(实例数据),Padding(对齐填充)

2.1 对象头

1)自身运行时的数据,即标志信息(Mark Word)

     ●哈希码:对象的唯一标识符

     ●对象的分代年龄:与垃圾回收有关

     ●线程持有的锁

     ●锁的状态

     ●偏向线程ID、偏向时间戳

     ●数组长度:如果该对象是数组,会有数组长度信息

下图是HotSpot虚拟机对象头 MarkWord

2)类型指针,即元信息指针(Kclass Pointer)

     ●元信息指针是指向方法区中类的元数据的指针,虚拟机通过这个指针来确定是哪个类的实例。(并非一定需要的,如果是数组还会存在数组的长度)

2.2 实例数据

实例的信息存放的是一些对 Java 使用者真正有效的信息,也就是类中定义的各个字段,其中还包括从父类继承的字段。这部分的存储顺序会受到虚拟机分配日策略和字段在Java源码中定义的顺序的影响。HotSpot虚拟机所默认的分配的策略时相同宽度的字段分配在一起,如(Longs/doubles ,  shorts/chars)

2.3 对齐填充

对其填充这段内存段存在与否取决于前面两部分的长度,为了保证对象内存模型的长度为 8 字节的整数倍,这也是虚拟机自动内存管理的要求。

3. 对象的访问定位

对象创建起来之后,就会在虚拟机栈中维护一个本地变量表(局部变量表),用于存储基础类型和基础类型的值,引用类型与引用类型的值。

其中引用类型的值就是堆中对象地址。如何引用堆中地址有两种方式:

     ●直接指针:对象的地址直接存储在栈中,这样做的好处就是访问速度变化快

     ●句柄:在堆中维护一个句柄池,句柄中包含了对象地址,当对象被移动的时候(垃圾收集时移动对象是非常普遍的行为),只需改变句柄,不需要改变栈中本地变量表中reference的引用(指向句柄池)

注意:句柄访问时,句柄池里不仅存了实例数据指针,还存了对象数据类型指针。而直接访问时,对象类型指针就放在实例池里

像HotSpot采用的就是直接指针的方式

关于句柄访问可以看下这篇博文:https://blog.csdn.net/u012481172/article/details/50936815

猜你喜欢

转载自blog.csdn.net/qq_36582604/article/details/81583059