## 對象的內存布局
在HotSpot虛擬機中,對象的內存布局分為以下3個區域:
* 對象頭
* 實例數據
* 對齊填充

### 對象頭
對象頭包含Mark Word和類型指針2個部分。如果是數組對象,則有一部分存儲數組的長度。
Mark Word中存儲:
* 哈希嗎(HashCode)
* GC分代年齡
* 鎖狀態標志
* 線程持有的鎖
* 偏向線程ID
* 偏向時間戳
### 類型指針
類型指針Klass存儲該對象的類對象的內存地址,可以通過該指針知道對象是屬于哪個類。
### 實例數據
實例數據部分就是成員變量的值,其中包括父類成員變量和本類成員變量。
### 對齊填充
保證對象內存大小是8字節的倍數,不足的部分按填充對齊。
## 參考資料
* 周志明 * 《深入理解Java虛擬機》
## 對象的創建過程

1. 類加載檢查
先檢查對象的類是否加載,沒有加載則先加載類。(類加載完成后就能計算出對象的大小,請參考[Java如何計算對象大小](%E5%A6%82%E4%BD%95%E8%AE%A1%E7%AE%97%E5%AF%B9%E8%B1%A1%E5%A4%A7%E5%B0%8F.md)
2. 內存分配
給對象分配內存,如果使用TLAB,則優先在TLAB空間分配,再在Eden區分配。如果內存規整則使用指針碰撞方式分配內存,不規整則使用空閑列表方式分配內存。
* 指針碰撞
內存規整(說明垃圾回收采用的是標記整理算法),已使用內存和空閑內存分界線上放著一個指針左為分界指示器。只需要將指針移動往空閑內存一端移動對象大小的距離。
* 空閑列表
內存不規整(說明垃圾回收采用的是標記清除算法,有碎片),那么VM必須維護一個列表,記錄哪些內存是空閑可用的,分配時從空閑列表中找到一塊足夠大的內存給對象示例使用。
3. 初始化
* 設置零值
內存分配完成后,虛擬機會將分配到內存的空間都初始化為零值。(不包含對象頭)
這也保證了Java代碼不賦值初始化就直接使用,程序能訪問到這些字段的數據類型對應的零值。
* 設置對象頭信息
-- 設置klass指針為對應類對象的地址
-- 對象的hashCode
-- 對象的分代年齡 等
* 執行構造方法`<init>`
執行對象所屬類定義的`init`構造方法,完成初始化。
至此,一個可用的對象才算是完全創建出來。
## 對象的訪問方式
對象的存儲空間是在堆中分配的,但是這個對象的引用(存的是地址)卻是在棧中分配的。
Java程序通過棧上的`reference`引用來操作堆上的具體對象。
目前對象的訪問方式有句柄訪問和直接指針訪問方式。
### 句柄訪問方式

對象引用內存儲的是指向句柄地址,句柄對象中包含對象實例數據指針和類型數據指針。
### 直接指針訪問方式

對象引用中存儲的是對象實例數據指針,再通過對象頭里的klass指針找到對象類型數據。
總結:
使用句柄方式訪問,優點是對象變化時棧中的reference的值不用改變,存儲的是穩定的句柄地址;
而使用直接指針方式訪問最大好處就是速度更快,它節省了一次指針定位的時間開銷。
HotSpot虛擬機采用直接指針的對象訪問方式。
- 面試突擊
- Java虛擬機
- 認識字節碼
- 000Java發展歷史
- 000Macos10.15.7上編譯OpenJDK8u
- 001熟悉Java內存區域
- 002熟悉HotSpot中的對象
- 003Java如何計算對象大小
- 004垃圾判定算法與4大引用
- 005回收堆和方法區中對象
- 006垃圾收集算法
- 007HotSpot虛擬機垃圾算法實現篇1
- 007HotSpot虛擬機垃圾算法實現篇2
- 007HotSpot虛擬機垃圾算法實現篇3
- 008垃圾收集器
- 009內存分配與回收策略
- 010Java虛擬機相關工具
- 011調優案例分析
- 012一次IDEA的啟動速度調優
- 013類文件Class的結構
- 014熟悉字節碼指令
- 015類加載機制(過程)
- 016類加載器
- IDEA的JVM參數
- Java基礎
- Java自動裝箱與拆箱
- Java基礎數據類型
- Java方法的參數傳遞
- Java并發
- 001走入并行的世界
- 002并行程序基礎
- 003熟悉Java內存模型JMM
- 004Java并發之volatile關鍵字
- 005線程池入門到精通
- 006Java多線程間的同步控制方法
- 007Java維基準測試框架JMH
- 008Java并發容器
- 009Java的線程實現
- 010Java關鍵字synchronized
- 011一些并行模式的熟悉
- 單例模式和不變模式
- 生產者消費者模式
- Future模式
- 012一些并行算法的熟悉
- 面試總結
- 長亮一面