这是我参与8月更文挑战的第1天
java中最常见的操作,new一个对象.但是new对象过程中jvm是如何运行的?本篇文章以HotSpot虚拟机为例,简单探秘下new对象的整个流程。
以最常用的虚拟机hotspot和最常用的内存区域Java堆为例(本篇文字概念较多):
1、对象创建
当java虚拟机遇到一条字节码new指令时--->是否在常量池中定位到一个类的符号引用--->虚拟机为新生对象分配内存(如果堆中内存绝对规整,指针碰撞。反之 空闲列表)。
指针碰撞:
所有使用过的内存在一边,空闲的内存在一边。中间放着一个指针作为分界点的指示器,内存分配是只需要吧指针向空闲方向移动一段与对象大小相等的距离。空闲列表:
维护一个列表,记录哪些内存快是可用的,如果划分给了对象实例,则更新列表上的记录。2、对象的内存布局
对象在堆内存中的存储布局可以划分为三个部分:对象头(Header)、实例数据(Instance Data)和对象填充(Padding)
对象头包含两部分信息:
Mark Word:
用于存储对象自身的运行数据,如果哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程Id、偏向时间戳。类型指针:
对象指向它的类型元数据的指针,如果对象是一个数组,要在对象头中必须有一块用于记录数组长度的数据实例对象:
程序代码里面所定义的各种类型的字段内容(包括父类继承下来的)3、对象访问定位
对象访问方式由虚拟机实现而定,在栈中指向堆时,主流的访问方式主要有使用句柄和直接指针两种。
句柄访问:
java堆中可能会划分出一块内存为句柄池,reference中存储的就是对象的句柄地址。句柄中包含了对象实例数据与类型数据各自的地址信息。指针访问:
referenc中存储的直接就是对象的地址。对比:句柄访问最大的好处就是reference中存储的是稳定句柄地址,当对象被移动时,只需要更改句柄中实例数据指针,而reference本身不需要被修改。指针访问速度快