《JVM学习系列》二.HotSpot虚拟机对象解密
来源:互联网 发布:清除数据恢复出厂英文 编辑:程序博客网 时间:2024/05/18 23:29
0.背景
上篇文章介绍了Java虚拟机的运行时的数据区之后,这篇继续探寻这些虚拟机的其他细节,比如对象是如何创建的、如何布局以及如何访问的。对于这样涉及细节的问题,必须吧讨论限定在具体的虚拟机和集中在某一个内存区域上才有意义。下面一常用的HotSpot虚拟机和常用的内存区域Java堆为例,探讨HotSport虚拟机在Java堆中对象分配、布局和访问的全过程。
1.对象的创建
虚拟机遇到一条new指令时,会经过以下流程来创建对象
1.1首先会检查这条指令的参数是否在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载、解析和初始化,如果没有,则必须先执行相应的类加载过程
1.2当类加载检查后,接下来虚拟机就为对象分配内存。为对象分配内存就等同于把一块内存从Java堆中划分出来。这里划分分两种情况:
1.假如Java堆中的内存是绝对规整的,所有用过的内存都放在一边,空闲的内存放在另一边,中间放着一个指针作为分界点的指示器,那么划分的过程就是将指针向空闲的内存空间挪动一个对象大小相等的距离。这种方式称为“指针碰撞”。2. 如果Java堆中的内存不是规整的,虚拟机就需要维护一个列表,记录上哪些内存块是可用的,在分配的时候找到一块足够大的内存,分配给对象实例,并更新列表,这种配置方式称为“空闲列表”。
1.3给对象实例分配内存空间时,在并发情况下,修改指针指向并不是线程安全的,可能一个线程正在给对象A分配内存,指针还没有来得及修改,对象B又同事使用了原来的指针来分配内存的情况。
解决这个问题有两种方案:
1.对分配内存空间的动作进行同步处理—— 实际上虚拟机采用CAS配上失败重试的方式来保证更行操作的原子性。2.对分配内存空间的动作按照线程划分在不同的空间中进行。即为每一个线程在Java堆中预先定义一小块内存,称为本地线程分配缓存。
1.4内存分配完成后,Java虚拟机将分配的内存空间都初始化为零值(不包括对象头)。这一部分操作保证了对象实例的字段在Java代码中可以不赋初始值就可以直接使用,程序能访问到这些字段的数据类型所对应的零值。
1.5接下来,虚拟机需要对对象实例进行必要的设置,比如这个对象是哪个类的实例,如何找到类的元数据,对象的哈希码,对象的GC分代年龄等信息。这些信息存放在对象的对象头中。
1.6 执行完new指令后接着执行init方法,把对象按照程序员的意愿进行初始化,这样一个对象就初始化完成了。
2. 对象的内存布局
在HotSpot虚拟机中,对象在内存中的布局分为三块区域:对象头,实例数据,和对齐填充。
2.1 对象头
HotSpot的对象头分为两部分:
第一部分用于存储对象自身的运行时数据,如哈希吗,GC分代年龄,锁状态标志,线程持有的锁,偏向线程的ID,偏向时间戳等。
第二部分是类型指针,即对象指向他的类元数据的指针,虚拟机通过这个指针来确定对象是哪个类的实例。如果对象是一个Java数组,那在对象头中还必须有一块用于记录数组长度的数据。
并不是所有的虚拟机实现都必须在对象数据上保留类型指针,换句话说,查找对象的元数据信息并不一定要经过对象本身。
2.2 实例数据
实例数据是对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段
内容,在父类中定义的变量会出现在子类之前,如果CompactFields参数值为true,那么子类
中较窄的变量也可能会插入到父类变量的空隙之中。
2.3 占位符
第三部分对齐填充并不是必然存在的,也没有特别的含义,它仅仅起着占位符的作用。不满8
个字节的时候占位。
3.对象的访问定位
Java程序需要通过栈上的Reference数据来操作堆上的具体对象。Reference访问对象的方式目前主流的有两种:句柄和直接指针。
3.1 使用句柄
使用句柄访问,java堆中将会划分出一块内存来作为句柄池,reference中存储
的是对象的句柄地址,而句柄中包含了对象数据与类型数据各自的具体地址信息,如下
图所示。
3.2 使用直接指针
使用直接指针访问,那么java堆对象的布局中就必须考虑如何放置访问类型数据的相关信息,而reference中存储的直接就是对象地址,如下图所示
这两种对象访问方式各有优势,使用句柄来访问的最大好处是reference中存储的是稳定的句
柄地址,在对象被移动时只会改变句柄中的实例数据指针,而reference本身不需要修改。
使用直接指针访问方式的最大好处就是速度更快,它节省了一次指针定位的时间开销。
HotSpot虚拟机使用的是直接指针访问的方式。句柄来访问的情况也十分常见。
- 《JVM学习系列》二.HotSpot虚拟机对象解密
- JVM学习笔记(二)HotSpot虚拟机对象探秘
- JVM(二):HotSpot虚拟机对象探秘
- JVM虚拟机-对象(HotSpot)
- 深入理解JVM(二):hotspot虚拟机对象
- JVM笔记(二)——HotSpot虚拟机对象
- 《JVM学习系列》三.HotSpot虚拟机对对象的回收
- (二)-HotSPot虚拟机对象探秘
- (二)HotSpot虚拟机对象
- JVM学习(2)-HotSpot对象
- 深入理解JVM:HotSpot虚拟机对象探秘
- JVM虚拟机系列二
- jvm hotspot虚拟机研究
- Java虚拟机学习记录,HotSpot对象创建
- JVM系列二(虚拟机对象创建、布局、定位)
- HotSpot虚拟机对象探秘
- HotSpot虚拟机对象探秘
- HotSpot虚拟机对象探秘
- Python 教程
- Android studio 快捷键及使用技巧
- C#之你该知道的东西1.0
- linux c实现文件复制
- Class类的使用——课后总结
- 《JVM学习系列》二.HotSpot虚拟机对象解密
- Problem 50 Consecutive prime sum (线性筛)
- typedef 的用法
- c语言读写函数
- android Studio Lambda插件(gradle-retrolambda)安装
- 2. 使用Python 解释器
- 拉格朗日(Lagrange)插值曲线
- IOC控制反转手记
- unity 3d中如何创建公有共用的代码段或数据,让所有其他类或者脚本都能访问?(代码说明static 静态类的使用)