創(chuàng)建
1.遇到new指令
2.檢查指令的參數(shù)能否在常量池中定位到一個(gè)類的符號引用。并檢查這個(gè)符號對應(yīng)的類是否被加載、解析和初始化
3.沒有則先加載類(類的加載過程)
4.分配堆內(nèi)存(兩種方式)
- 指針碰撞:在規(guī)整的堆內(nèi)存中把用于劃分空閑和已使用的指針往空閑方向挪動(dòng)相應(yīng)的距離。(適用整理類算法:Serial、ParNew)
- 空閑列表:非規(guī)整內(nèi)存時(shí),用來維護(hù)可用內(nèi)存塊的列表。(使用清除類算法:CMS)
使用哪種方式取決于JVM使用的垃圾回收器
分配內(nèi)存時(shí)的線程安全問題:
- CAS+失敗重試
- 本地線程分配緩沖(TLAB):把內(nèi)存分配的按照線程劃分在不同的空間進(jìn)行,也就是每個(gè)線程預(yù)分配一小塊內(nèi)存
5.將分配到的內(nèi)存空間都初始化為0值(TLAB需要提前進(jìn)行),這保證了對象的實(shí)例字段不賦初始值就可以使用。
6.設(shè)置對象頭中的信息(元數(shù)據(jù)、對象hash code、GC分代年齡、鎖)
7.以上JVM的操作完成,交給java線程執(zhí)行init。
布局
對象頭+實(shí)例數(shù)據(jù)+對齊填充
1.對象頭(Mark Word + 類型指針)
| 存儲內(nèi)容 | 標(biāo)志位 | 狀態(tài) |
|---|---|---|
| 對象哈希碼、分代年齡 | 01 | 未鎖定 |
| 指向鎖記錄的指針 | 00 | 輕量級鎖定 |
| 指向重量級鎖的指針 | 10 | (膨脹)重量級鎖定 |
| null | 11 | GC標(biāo)記 |
| 偏向線程ID、偏向時(shí)間戳、對象分代年齡 | 01 | 可偏向 |