2 Java内存层面的对象认识
说明:此分析基于HotSpot虚拟机
1 对象的创建
Java对象的创建方式有三种:
- 通过new创建
- 通过反序列化创建
- 通过复制创建
通过new方式的对象创建过程如下:
创建过程说明:
- 执行字节码遇到new指令时,首先将去检查这个指令的参数是否能在常量池中定位到 一个类的符号引用。
- 类的初始化过程在后续章节详细补充
- 给对象分配初始内存空间有两种方式:指针碰撞 和 空闲列表。
- 分配空间后,清空该段的【不包括对象头】值,保证对象属性的不设值就使用初始值
- 对象头信息包括:元数据信息、对象的哈希码、对象的GC分代年龄
- 执行构造函数,给属性初始化设置的值
2 对象的内存布局
对象存储的内容分类以及明细如下:
一、关于对象头的补充说明:
- 对象头,在字长为32位和64位的虚拟机中分别为32比特(4字节)64比特(8字节)。
- 对象头的类型指针:不一定所有对象都会存储这项信息,意味着访问对象所属的类不一定通过对象自身。
- 如果对象是一个Java数组,那在对象头中还必须有一块用于记录数组长度的数据。
二、关于实例数据的补充说明:
- 对象属性的存储顺序,受到虚拟机分配策略参数(-XX:FieldsAllocationStyle参数)和字段在Java源码中定义顺序的影响
- 默认的分配策略下:占据相同字节数的属性会排列在一起,满足该条件下,父类的属性排在前面。
三、关于对齐填充的说明:
- 不一定会存在,因为对象的大小一定是8字节的整数倍,因此需要对齐填充这部分,充当占位符
在32位字长的虚拟机下,对象的内存分布情况如下:
对象头的MarkWord部分:
注:MarkWord结构在《synchronized详解》会涉及
3 对象的访问定位
对象访问方式也是由虚拟机实现而定的,主流的访问方式主要有使用句柄和直接指针两种:
3.1句柄访问
说明:
句柄访问方式,Java堆中将可能会划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自具体的地址
3.2 直接指针访问
说明:
使用直接指针来访问最大的好处就是速度更快,只需要一次定位就能找到实例数据,而句柄池则需要两次:(需要先定位句柄池,再定位实例数据)