对象的创建
当VM遇到一条new的指令时,先查找常量池,看是否能定位到一个符号引用,检查类是否被类加载器加载、解析、初始化(?)
如果不满足检查条件,则进行类加载过程,在过程结束时可以确定需要分配给该类的内存大小
根据VM管理的堆内存是否规整--取决与垃圾回收器是否有压缩整理内存的功能--对于不规整的内存,采用FreeList方式给对象分配空间
如果规整则可以使用指针碰撞 bump the pointer方法来分配
考虑到创建对象是一个很频繁的动作,有可能并发,所以实际中一般会采用TLAB Thread Local Allocation Buffer 来预先给线程分配一定的
空间。只有当预分配空间不够用,申请新的空间时,对申请过程加锁对并发进行控制
VM的TLAB开关 -XX:+/-UseTLAB
内存分配完成后会给对象赋初始值,和确定对象的HashCode 年龄分代 锁等信息。此时从VM的角度看,对象已经创建完成。
但是仍需要执行init按照编程者的意愿进行初始化,一个可用的对象就正式完成。
对象的内存布局
在HotSpot虚拟机中,一个对象包含3个部分:对象头,实例数据,填充对齐
对象头中记录的信息分为两个部分 一是对象运行基本信息,如hashCode GC分代年龄 锁状态标志 线程持有的锁 等。第二个部分是类型指针
指向对象的元数据用以确定改对象是谁的实例。如果对象是一个数组,还需要在对象头中记录数组的长度
实例数据中记录的就是对象的有效信息,如字段值
填充对齐并不是必须的,HotSpot的VM规定对象起始地址最小为8bit,如果对象长度不够则会补齐
对象的访问
使用对象比如通过栈上的reference类型来确定对象的引用。一般有两种访问方式。一个是通过句柄,一个是使用直接指针访问
如果是通过句柄访问,在堆中会划分出句柄池。reference指向句柄池 句柄池中的一条句柄分别(两个指针)指向实例池中的对象实例
和方法区中的对象类型数据。
直接指针访问reference直接指向对象地址,且在对象中维护一个指向方法区的指针