类加载检查
java虚拟机在遇到一条 new 指令时,首先会检查是否能在常量池中定位到这个类的符号引用,而且是否已被加载过、解析和初始化过。若是没有,那必须先执行类加载过程java
类加载的相关知识可参考:JVM的类加载机制算法
分配内存
在类加载检查经过后,接下来虚拟机将为新生对象分配内存。并发
分配方式有 指针碰撞 和 空闲列表 两种线程
指针碰撞:Java堆中的内存是规整的,全部用过的内存都放在一边,空闲的内存放在另外一边,中间放着一个指针做为分界点的指示器,分配内存也就是把指针向空闲空间那边移动一段与内存大小相等的距离。指针
空闲列表:Java堆中的内存不是规整的,已使用的内存和空闲的内存相互交错,就没有办法简单的进行指针碰撞了。虚拟机必须维护一张列表,记录哪些内存块是可用的,在分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录对象
Java 堆内存是否规整,取决于 GC 的垃圾回收算法,在JVM中标记压缩、复制算法的内存是规整的、而标记清除则是不规整的内存
垃圾回收算法相关知识可参考:JVM垃圾收集算法详解虚拟机
内存分配并发问题
CAS操做:CAS是属于原子性操做,更多关于此内容可参考此内容:Java原子类操做原理剖析原理
TLAB: 为每个线程预先在Eden区分配一起内存,JVM在给线程中的对象分配内存时,首先在TLAB分配,当对象大于TLAB中的剩余内存或TLAB的内存已用尽时,再采用上述的CAS进行内存分配垃圾回收
内存空间初始化
内存分配完成后,虚拟机须要将分配到的内存空间都初始化为零值。这一步操做保证了对象的实例字段在 Java 代码中能够不赋初始值就直接使用,程序能访问到这些字段的数据类型所对应的零值。例如:
int a=1
long b=2
实际上在这时被赋值为了
a=0
b=0L
设置对象头
内存空间初始化完成以后,虚拟机要在对象头中保存如下必要的信息:
这个对象是那个类的实例
如何才能找到类的元数据信息
对象的哈希码
对象的 GC 分代年龄
等等
执行构造方法这里才是咱们最熟悉的地方