创建
1.遇到new指令
2.检查指令的参数能否在常量池中定位到一个类的符号引用。并检查这个符号对应的类是否被加载、解析和初始化
3.没有则先加载类(类的加载过程)
4.分配堆内存(两种方式)
- 指针碰撞:在规整的堆内存中把用于划分空闲和已使用的指针往空闲方向挪动相应的距离。(适用整理类算法:Serial、ParNew)
- 空闲列表:非规整内存时,用来维护可用内存块的列表。(使用清除类算法:CMS)
使用哪种方式取决于JVM使用的垃圾回收器
分配内存时的线程安全问题:
- CAS+失败重试
- 本地线程分配缓冲(TLAB):把内存分配的按照线程划分在不同的空间进行,也就是每个线程预分配一小块内存
5.将分配到的内存空间都初始化为0值(TLAB需要提前进行),这保证了对象的实例字段不赋初始值就可以使用。
6.设置对象头中的信息(元数据、对象hash code、GC分代年龄、锁)
7.以上JVM的操作完成,交给java线程执行init。
布局
对象头+实例数据+对齐填充
1.对象头(Mark Word + 类型指针)
存储内容 | 标志位 | 状态 |
---|---|---|
对象哈希码、分代年龄 | 01 | 未锁定 |
指向锁记录的指针 | 00 | 轻量级锁定 |
指向重量级锁的指针 | 10 | (膨胀)重量级锁定 |
null | 11 | GC标记 |
偏向线程ID、偏向时间戳、对象分代年龄 | 01 | 可偏向 |
网友评论