《深入理解Java虚拟机》学习总结-对象(创建过程,内存布局,访问定位)

一.对象的创建

当Java虚拟机遇到一条字节码new指令时,首先会去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并检查这个符号引用所代表的类是否已被加载、验证、准备、解析、初始化过,如果没有,那必须先执行相应的类加载过程。

类加载完成后,接下来虚拟机将为新生对象分配内存。对象所需内存大小在类加载完成后便可完全确定,内存分配完毕后,虚拟机必须将分配到的内存空间(不包括对象头)都初始化为0值,这步操作保证了对象的实例字段在Java代码中可以不赋初值就可以直接使用。

接下来,Java虚拟机还要对对象进行必要的设置,例如这个对象是哪个类的实例,如何才能找到类的元数据,对象的哈希吗(对象的哈希吗会延后到真正调用Object::hashCode()方法才计算)、对象GC分代年龄等信息。这些信息存放在对象头中。

上述工作完成后,从虚拟机的视角来看,一个对象已经产生了。但是从Java程序员的视角来看,对象创建才刚刚开始——构造函数,即Class文件中的<init>()方法还没有执行,所有字段都是默认的零值

二.对象的内存布局

HotSpot虚拟机中,对象在堆内存的存储布局可以划分为三个部分:对象头、实例数据和对齐填充

对象头部分:对象头部分包括两类信息。第一类是用于存储对象自身的运行时数据,如哈希码,GC分代年龄,锁状态标志,线程持有的锁,偏向线程ID,偏向时间戳等,这部分数据的长度在32位和64位的虚拟机中分别为32比特和64比特,官方称这部分数据为“Mark Word”

需要注意的是,为了节约空间,Mark Word被设计为一个有着动态定义的数据结构,即上图存储的五种内容,在一个时刻,只会出现其中一种内容,具体是存储的是什么类型的内容,要看该时刻对象的状态来决定。至于hash码没了怎么办,实际上,Java语言里面一个对象如果计算过哈希码,就应该一直保持不变,而绝大部分哈希码来源的Object::hashCode()方法,返回的是对象的一致性哈希码,这个值是强制保持不变的,所以当一个对象已经计算过一致性哈希码后,它就再也无法进入偏向锁状态了,而当一个对象正处于偏向锁状态,又收到需要计算一致性哈希码请求时,它的偏向状态会立即被撤销,并且锁会膨胀为重量级锁,在重量级锁的实现中,对象头指向了重量级锁的位置,代表重量级锁的ObjectMonitor类中有字段可以记录未锁定状态的Mark Word,而轻量级锁实现中,锁记录中也储存了未锁定状态的Mark Word,因此不用担心哈希码丢失

对象头的另一部分是类型指针,即对象指向它的类型元数据(元数据可以简单的理解为描述数据的数据)的指针,Java虚拟机通过这个指针来确定该对象是哪个类的实例。并不是所有虚拟机实现都必须在对象数据上保留类型指针,换句话说,查找对象的元数据信息不一定要经过对象本身。

实例数据部分:实例数据部分是对象真正存储的有效信息,即我们在程序代码里定义的各种类型的字段内容

对齐填充部分:这部分不是必然存在的,也没有特别的含义,它经济起着占位符的作用。由于HotSpot虚拟机的自动内存管理系统要求对象起始地址必须是8字节的整数倍,所以需要通过对齐填充来对奇。

三.对象的访问定位

对象的主流访问方式主要有句柄直接指针两种

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

直接指针访问:reference存储的直接就是对象地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值