深入理解java虚拟机之HotSpot虚拟机探秘

一、对象的创建

  1. 虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,则先执行相应的类加载过程。
  2. 接下来虚拟机将为新生对象分配内存。对象所需内存的大小在类加载完成后便可完全确定。
    • 假设java堆内存是绝对规整的,所有用过的内存都放在一边,空闲的内存放在另一边,中间放着一个指针作为分界点的指示器,那所分配内存就是仅仅是把那个指针向空闲空间那边挪动一段与对象大小相等的距离。称为“指针碰撞”。
    • 如果java堆中内存不是规整的,虚拟机就维护一个列表,记录哪些内存块是可用的,在分配时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录,这种分配方式称为“空闲列表”。选择哪种分配方式由java堆是否规整决定,而java堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能决定。
  3. 虚拟机需要将分配到的内存空间都初始化为零值,如果使用TLAB(本地线程分配缓冲),这一工作过程也可以提前至TLAB分配时进行。
  4. 虚拟机要对对象进行必要的设置。必要信息都会存放在对象的对象头之中。
  5. 执行new指令之后会接着执行<init>方法,把对象按照程序员的意愿进行初始化。

二、对象内存布局

对象在内存中存储的布局可以分为3块区域:对象头(Header)、实例数据(instance Data)和对齐填充(Padding)。

  • 对象头包含两部分信息:第一部分用于存储对象自身的运行时数据。这部分数据的长度在32位和64位的虚拟机(未开启压缩指针)中分别为32bit和64bit,称为“Mark Word”;第二部分是类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。如果对象是java数组,那在对象头中还必须有一块用于记录数组长度的数据。
  • 实例数据存储对象真正的有效信息,就是程序代码中定义的各种类型的字段内容。
  • 对齐填充并不是必然存在,也没有特别的含义,它仅仅起着占位符的作用。


三、对象访问定位

对象的访问方式取决于虚拟机实现而定的,目前主流的访问方式有使用句柄和直接指针两种

  • 使用句柄访问的话,在堆中会划出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自的具体的地址信息《深入理解java虚拟机之HotSpot虚拟机探秘》
  • 使用直接指针访问,堆对象的布局就必须考虑如何放置访问类型数据的相关信息,而reference中存储的直接就是对象地址。

《深入理解java虚拟机之HotSpot虚拟机探秘》

使用句柄好处就是对象移动时只会改变句柄中的实例数据指针,而reference本身不需要修改。 使用直接指针访问方式最大好处就是速度更快。

参考自《深入理解Java虚拟机》

    原文作者:java虚拟机
    原文地址: https://blog.csdn.net/owen1190/article/details/52141992
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞