theme: condensed-night-purple
1.对象的创建
前言:Java对象创建过程:限于普通对象,不包含数组和Class对象(JVM生成的Class对象)
流程图
1.类加载检查
检查该new指令的参数 是否能在 常量池中 定位到一个类的符号引用
检查 该类的符号引用 代表的类是否被加载过
2.分配内存
对象在类加载完成后,具体的大小就能确定出来, 此时需要在java堆里面划分内存
划分内存方式根据“Java堆内存是否绝对规整”为依据分为两种方式:
1.指针碰撞(规整)
分配形式:在已使用内存中间放一个分界点的指示器 ;分配对象内存 = 把指针向未使用内存 移动一段 与对象大小相等的距离
2.空闲列表(不规整)
分配形式:虚拟机维护着一个 记录可用内存块 的列表,在分配时从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录
Java堆内存是否绝对规整概念:如果已使用内存和未使用内存分别在两边,没有交错,这就是绝对规整。
Java堆内存是否绝对规整是由“垃圾收集器是否带有压缩整理功能(Compact)决定”:因此Serial,ParNew采用指针碰撞。CMS采用空闲列表
注意:分配内存线程不安全问题;
例如:当前正在给A分配对象,指针还没来的及修改,B已经在拿原来的指针位置来分配内存了
解决方案:
同步处理分配内存空间的行为(CAS+失败重试的方式,保证更新操作的原子性,cpu消耗大)
把内存分配根据线程划分,在各自的线程中进行分配。即每个线程先在Java堆里面预先分配一小块内存,如果分配完了,则重新再分配内存,此时需要**同步锁**
3.将内存空间初始化为零值
内存分配完成后,虚拟机需要将分配到的内存空间初始化为零(不包括对象头)
4.对对象进行必要的设置
设置 这个对象 是哪个类的 实例,如何才能找到类的元数据信息,对象的HashCode,对象的GC分代年龄
对象的内存布局
-
问题:在
Java对象创建后,到底是如何被存储在Java内存里的呢? -
答:在
Java虚拟机(HotSpot)中,对象在Java内存中的 存储布局 可分为三块:
1.对象头 存储区域
对象自身的运行时数据(如HashCode),GC分代年龄,锁状态标志,线程持有的锁
对象类型指针(对象指向它的类元数据指针,虚拟机通过这个对象来确定是哪个类的实例)
注意:如果是数组。对象头还有一块比心记录数组长度的数据
2.实例数据 存储区域
代码中定义的字段内容
3.填充 存储区域
占位符(因为大小必须是8字节的整数倍,对象头刚好是8字节的倍数。当实例的数据带下不是8字节的整数倍时候,则就用它来填充至8的倍数)