Java虚拟机对象创建过程

1、对象的内存分配方法

  1. 类加载检查,首先检查类是否已被加载、解析和初始化过。如果没有,那必须先执行相应的类加载过程。

  2. 类加载检查通过之后,需要为新生对象分配内存,分配内存有两种方法:

    • **指针碰撞**

    • **空闲列表**

  3. 对象创建应该是线程安全的,例如给对象分配完内存之后,需要修改栈区中指向堆内存堆的指针,这个过程未必是线程安全的。实现内存分配指针修改的线程安全,有两种方法:

    • **CAS配上失败重试**保证更新操作的原子性

    • **本地线程分配缓冲**(Thread Local Allocation Buffer,TLAB),为每一个线程在Java堆中预先分配一小块内存,只有本地缓冲区用完之后,分配新缓存区才需要同步锁定

  4. 内存分配完成之后,虚拟机必须将分配到的内存空间(但不包括对象头)都初始化为零值,保证了在Java代码中可以不赋初始值就直接使用

  5. **对象头**进行设置,对象头包括:

    • 类的元数据信息

    • 对象的哈希码

    • 对象GC分代年龄

  6. 对对象进行初始化,包括执行构造函数、静态代码段执行


2、对象的内存把布局

  1. 对象在内存中的存储布局可以分为三个部分:

    • 对象头

    • 实例数据

    • 对齐填充

  2. 对象头包括两部分信息

    • 对象运行时数据,包括哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等,这部分数据的长度在32位和64位的虚拟机(未开启压缩指针)中分别为32个比特和64个比特,官方称它 为“Mark Word”

    • 对象类型指针,即对象指向它的类型元数据的指针,Java虚拟机通过这个指针 来确定该对象是哪个类的实例

  3. 实例数据,对象真正存储的有效信息,即我们在程序代码里面所定义的各种类型的字段内容

  4. 对齐填充

    • HotSpot虚拟机的自动内存管理系统要求对象起始地址必须是8字节的整数倍,换句话说就是 任何对象的大小都必须是8字节的整数倍,对不满足要求的部分进行填充。


3、对象的定位访问

  1. 对象的访问方式主要有两种:

    • 句柄访问

    • 直接访问

  2. 句柄访问

    • reference存放的是对象句柄地址,包括**对象实例数据****类型数据**,实例数据位于堆内存中,指的是类中的各个字段。类型数据即对象的方法,位于方法区,由对象头中的对象类型指针指向

    • 句柄访问的好处在于reference中存储的是稳定句柄地址,在对象被移动(垃圾收集时移动对象是非常普遍的行为)时只会改变句柄中的实例数据指针,而 reference本身不需要被修改。

  1. 直接访问

    • reference存储的是对象地址,避免了指针间接访问的开销

posted @ 2021-01-07 14:48  LiBai1  阅读(59)  评论(0)    收藏  举报