当虚拟机遇到new指令的时候
检查、确认内存大小和分配内存、初始化内存空间
1.检查指令的参数能否在常量池中定位到一个类的符合引用,并且检查这个符号引用代表的类有没有被加载、解析和初始化过
2.如果没有,则执行类加载过程
3类加载检查通过后,便可以确认对象所需的内存大小,如何进行分配内存
4.指针碰撞:可以理解为一边是使用的内存一边是空的,夹在中间的指针,分配内存的时候就是指针往空的内存挪一丢丢距离,即和对象所需内存大小一样的内存空间。 高效简单!
5.空闲列表:就是内存不够整齐,坑坑洼洼的,得专门记录哪块内存可用,分配时找到大的内存空间给对象。比较复杂!
6.如果是使用复制算法和标记压缩法 使用指针碰撞
如果是使用标记清除算法,则使用空闲列表
7.分到内存后要将分配到的内存空间都初始化为0,不包含对象头(不知道为什么,日后研究)
8.设置对象,将一些信息存放到对象头(哪个类的实例,如何找到类的元数据信息,hash码,GC分代年龄)。到这一步对象就产生了!
对象的内存布局
1.对象头(两部分)
Mark World:存放运行时数据(hashcoad,GC分代年龄,锁的状态标志,线程持有的锁)
类型指针:对象指向它的类型元数据指针
2.实例数据
3.对齐填充:占位符作用
对象的访问定位:通过栈的reference
1.句柄访问:Java堆中专门划分内存当作句柄池,reference存储的是对象的句柄地址
好处:储存的是稳定的句柄地址,GC时候对象位置发生变化只需要修改句柄中的实例数据指针
2.直接指针访问:referenc直接存储的是对象地址,速度较快