HotSpot虚拟机在Java堆中对象分配、布局和访问的全过程

1.对象的创建

1>虚拟机中遇j到一个new指令时,将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。

  如果没有,那必须先执行相应的类加载过程

2>在类加载检查通过后,接下来虚拟机将为新生对象分配内存

3>内存分配完成后,虚拟机需要将分配到的内存空间都初始化为零值(不包括对象头)

4>虚拟机对对象进行必要的设置,实际上是对对象头进行设置如:对象是哪个类的实例、如何才能找到对象的元数据信息、对象的哈希码、对象的GC分代年龄等信息

上面的步骤都完成,从虚拟机角度来看,一个新的对象已经产生了,但从Java程序的角度来看,对象的创建才刚刚开始——<init>方法还没有执行,所有的字段都还为零。

5>执行new指令后会接着执行<init>方法(由invokespecial指令所决定),把对象按照程序员的意愿初始化,这样一个真正可用的对象才算完全产生出来。

2.对象的内存布局

  在HotSpot虚拟机中,对象在内存中存储的布局可以分为3块区域:对象头、实例数据、和对其填充

  对象头包括两部分:1>用于存储对象自身的运行时数据   2>类型指针(对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例)

    对象自身的运行时数据这部分数据长度在32位和64位的虚拟机中分别为32bit和64bit,官方称它为“Mark Word”

  实例数据:是对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容。

    这部分的存储顺序受到虚拟机分配策略参数和字段在Java源码中定义顺序的影响。HotSpot VM默认的分配策略为longs/doubles  ints shorts/chars bytes/booleans oops ,

    从分配策略可以看出,相同宽带的字段总是被分配到一起。在满足这个条件的基础上,在父类中定义的变量会出现在子类之前。如果CompactFields参数值为true默认为true,

    那么子类之中较窄的变量也可能会插入到父类变量的空隙之中。

  对齐填充:不是必然存在的,也没有特别的含义,仅仅起着占位符的作用。由于HotSpot VM的自动内存管理系统要求对象起始地址必须是8字节的整数倍,即对象的大小必须是8字节的整数倍

    因此当对象实例数据部分没有对齐时,就需要通过对齐填充来补全

3.对象的访问定位

  Java程序需要通过栈上的reference数据来操作堆上的具体对象。

  主流的访问方式:句柄、直接指针 

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

    句柄好处:reference中存储的是稳定的句柄地址,在对象被移动时,只会改变句柄中的实例数据指针,而reference本身不需要修改

  直接指针:Java对象的布局中必须考虑如何放置访问类型数据的相关信息,而reference中存储的直接就是对象地址

    直接指针好处:速度更快,节省了一次指针定位的时间开销,HotSpot是使用这种方式进行对象访问的。

原文地址:https://www.cnblogs.com/hong0632/p/8707722.html