类检查器
虚拟机遇到一条new指令的时候,首先将去检查这个指令的参数是否能在常量池中定位到这个类的符号引用,并且检查这个行号引用代码的类是否被加载过、 解析过、初始化过.如果没有,则必须先进行相应的类加载过程.
分配内存
在类加载检查通过之后,接下来虚拟机将会为新生的对象分配内存. 对象所需要的内存大小在类加载完成之后便会确定,为对象分配内存空间的任务等同于把一块确定大小的内存从java堆中划分出来.分配方式有指针碰撞和空闲列表两种方式,选择哪种分配方式由java堆是否规整决定,而java堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能决定.
分配内存的方式
分配内存的方式最终取决于GC收集器的算法是"标记-清除"还是"标记-整理(标记-压缩)"
并发情况下的内存分配
可能会出现正在给对象A分配内存,指针还没来得及修改,对象B又使用了原来的指针来分配内存的情况,解决这个问题有两种方案。
方法一:
对分配内存空间的动作进行同步处理——实际上虚拟机采用CAS配上失败重试的方式保证更新操作的原子性
方法二:
把内存分配的动作按照线程划分在不同的空间之中进行,即每个线程在Java堆中预先分配一小块内存,称为本地线程分配缓冲(Thread Local Allocation Buffer,TLAB)。哪个线程要分配内存,就在哪个线程的TLAB上分配,只有TLAB用完并分配新的TLAB时,才需要同步锁定
初始化零值
内存分配完成之后,虚拟机要对对象进行必要的设置 , 如这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息.这些信息存放在对象头中.另外,根据虚拟机当前运行状态的不同,如是否启用偏向锁等, 对象头会有不同的设置方式
执行init方法
在上面的工作都完成之后,以虚拟机的视角来看,对象创建才刚开始,<init>方法还没有被执行,所有的字段值还都为零.所以一般来说,执行new指令之后接着执行方法,把对象按照程序员的意愿进行初始化,这样一个真正的对象才算完全产生出来.
参考:https://blog.csdn.net/wangzhi44444/article/details/99704540