首页 > 其他 > 详细

HotSpot虚拟机对象探秘

时间:2020-07-23 09:11:51      阅读:97      评论:0      收藏:0      [点我收藏+]

1.对象创建

  对象的创建通常(例外:复制、反序列化)只是一个new关键字而已。在虚拟机中,当虚拟机遇到一条字节码new的指令时,会根据指令的参数看是否能在常量池中定位到一个符号引用,并且检查这个符号引用对应的类是否被加载、验证、准备、解析、初始化过,如果没有,虚拟机就会根据符号引用去加载相应的类为新生的对象分配内存。

  对象所需要的内存大小在类加载完成之后即可确定(后面讲),为对象分配空间的任务等同于把一块对象内存大小的块从堆中划分出来。这里介绍两种内存划分方式:

(1)指针碰撞:假设堆内存是一块绝对规整的内存,把所有使用过的内存集中放在一边,没有使用过的内存集中放在另一边,中间以指针分割,那么对象的内存划分就是把指针向未使用过内存的方向移动对象内存大小相等的距离。如图:

技术分享图片

 

 

(2)空闲列表:如果java堆不是规整的,已使用的内存和未使用的内存交错在一起,就能不能使用指针碰撞了,虚拟机就必须维护一张表,记录哪些内存是可用的,在分配的时候从列表中找到一块足够大的内存划分给实例对象,并更新表上记录。

  选择哪种分配方式由java堆是否规整决定,而java堆是否规整又由所使用的垃圾回收器是否带有空间压缩整理(Compact1的能力决定。因此,在使用Serial、ParNew等带有空间压缩整理能力的垃圾收集器时,系统采用的分配算法是指针碰撞,简单高效;而当使用CMS基于清除算法的收集器时,理论上只能采用空闲列表来分配内存。

  另外,除了划分可用空间的难题外,还有一个需要考虑的问题是:对象在虚拟机中创建是非常频繁的行为,在指针碰撞中仅仅修改指针移动的位置,在并发情况下也不是线程安全的,可能会出现给A对象分配内存,指针还没来的及移动,对象B又使用了原来的指针来分配内存。

  解决这个问题有两种方案:一种是对内存分配这个动作进行同步处理——实际上虚拟机采用CAS配上失败重试的方式保证更新操作的原子性;另一种是把内存的分配动作按照线程划分的区域内进行,即在堆中给每个线程划分一块区域,线程创建的对象分配在对应的内存区域中,只有对应内存区域使用完毕,在进行分配内存时进行同步锁定。

  在内存分配完成之后,虚拟机需要将分配到的内存空间(不包括对象头)都初始化为零值,如果是在线程所对应的内存区域中,该项工作也可以提前到在线程对应内存区域划分对象内存后顺便进行。这步操作保证了对象的实例字段在使用过程中不赋值就可以使用,访问到的实例字段的数据类型对应为零值。

  你以为对象创建结束了? 不,远远没有。

2.对象内存布局

  在HotSpot虚拟机中,对象在堆中内存布局可以划分为以下三个部分:对象头【Header】、实例数据【Instance Data】、对齐填充【Padding】。

  HotSpot虚拟机对象中的对象头包含两类信息:

    第一类:用于存储对象自身的运行时数据,比如:哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。对象头中的信息是对象自身定义无关的额外存储成本。

    第二类:对象头的另一部分是类型指针,即对象指向对象的类型元数据的指针,Java虚拟机通过这个指针来确定该对象是哪个类型的实例。但并不是所有虚拟机实现都必须在对象数据上保留类型元数据的指针,换句话说,查找对象的元数据信息并不是一定要经过对象本身。

  实例数据部分是对象真正存储的有效信息,即我们在对象中定义的各种字段内容,无论是从父类继续下来,还是在子类中定义的字段都必须记录起来。该部分存储顺序受到虚拟机的分配策略参数和字段在java源码中定义顺序的影响。

  对象的第三部分是对齐填充,并不是必然,也没有特别含义,仅仅起个占位符的作用。由于HotSpot虚拟机的自动内存管理系统要求对象起始地址必须是8字节的整数倍,也就是说任何对象的大小都必须是8字节的整数倍。因此,如果对象实例数据部分没有对齐的话,就需要通过对齐填充来补全。

3.对象访问定位

  对象的创建之后后续的使用该对象,会通过栈上的reference数据来操作堆上的具体对象。在Java虚拟机规范中只规定了它是一个指向对象的引用,并没有定义以什么样的方式去定义、访问堆中的具体对象位置。对象的访问方式目前主流的有两种:使用句柄和直接指针。

  使用句柄访问的话,Java对中将划分一块内存作为句柄池,reference中存储的就是对象的句柄地址,句柄中包含了对象实例数据和类型数据各自的具体地址信息 如图所示:

  技术分享图片

 

 

  使用直接指针访问的话,Java堆中对象的内存布局必须考虑到如何放置类型数据的相关信息,如果reference中存储的直接就对象地址,实例中包含类型数据,这样访问对象本身的话,就不需要在多一次间接访问开销,如图:

技术分享图片

 

 

  

 

HotSpot虚拟机对象探秘

原文:https://www.cnblogs.com/Aaron-cell/p/13357835.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!