Java虛擬機JVM之Java對象的創建、內存佈局和訪問

這一小節將對 JVM 對 Java 堆中的對象的創建、佈局和訪問的全過程進行講解。

一、對象的創建

1、類加載檢查

虛擬機在解析.class文件時,若遇到一條 new 指令,首先它會去檢查常量池中是否有這個類的符號引用,並且檢查這個符號引用所代表的類是否已被加載、解析和初始化過。如果沒有,那麼必須先執行相應的類加載過程。

2、爲新生對象分配內存

對象所需內存的大小在類加載完成後便可完全確定,接下來從堆中劃分一塊對應大小的內存空間給新的對象。分配堆中內存有兩種方式:

  • 指針碰撞
    如果 Java 堆中內存絕對規整(說明採用的是“複製算法”或“標記整理法”),空閒內存和已使用內存中間放着一個指針作爲分界點指示器,那麼分配內存時只需要把指針向空閒內存挪動一段與對象大小一樣的距離,這種分配方式稱爲“指針碰撞”。

  • 空閒列表
    如果 Java 堆中內存並不規整,已使用的內存和空閒內存交錯(說明採用的是標記-清除法,有碎片),此時沒法簡單進行指針碰撞, VM 必須維護一個列表,記錄其中哪些內存塊空閒可用。分配之時從空閒列表中找到一塊足夠大的內存空間劃分給對象實例。這種方式稱爲“空閒列表”。

注意:除了如何爲新生對象分配內存之外,還需要注意在java虛擬機中創建對象是非常頻繁的事情,所以還需要考慮併發的問題,一共有兩種解決辦法:

  • 採用同步處理:java虛擬機採取CAS加失敗重試的方式
  • 使用本地線程分配緩衝(TLAB:Thread Local Allocation Buffer):按照線程劃分在不同的空間中進行;在線程初始化時,同時也會申請一塊指定大小的內存,只給當前線程使用,這樣每個線程都單獨擁有一個Buffer,如果需要分配內存,就在自己的Buffer上分配,這樣就不存在競爭的情況,可以大大提升分配效率,當Buffer容量不夠的時候,再重新從Eden區域申請一塊繼續使用,這個申請動作還是需要原子操作的。配置是否使用TLAB參數:-XX:UseTLAB

3、初始化

分配完內存後,爲對象中的成員變量賦上初始值,設置對象頭信息,調用對象的構造函數方法進行初始化。至此,整個對象的創建過程就完成了。

 

二、對象的內存佈局

在 HotSpot 虛擬機中,對象的內存佈局分爲以下 3 塊區域:對象頭(Header)、實例數據(Instance Data)、對齊填充(Padding)

對象的內存佈局

 

1、對象頭

對象頭記錄了對象在運行過程中所需要使用的一些數據:

  • 哈希碼
  • GC 分代年齡
  • 鎖狀態標誌
  • 線程持有的鎖
  • 偏向線程 ID
  • 偏向時間戳

對象頭可能包含類型指針,通過該指針能確定對象屬於哪個類。如果對象是一個數組,那麼對象頭還會包括數組長度。

2、實例數據

實例數據部分就是成員變量的值,其中包括父類成員變量和本類成員變量。

  • 默認分配順序:longs/doubles、ints、shorts/chars、bytes/booleans、oops (Ordinary Object Pointers),相同寬度的字段會被分配在一起,除了 oops,其他的長度由長到短;
  • 默認分配順序下,父類字段會被分配在子類字段前面。

3、對齊填充

用於確保對象的總長度爲 8 字節的整數倍。

HotSpot VM 的自動內存管理系統要求對象的大小必須是 8 字節的整數倍。而對象頭部分正好是 8 字節的倍數(1 倍或 2 倍),因此,當對象實例數據部分沒有對齊時,就需要通過對齊填充來補全。

對齊填充並不是必然存在,也沒有特別的含義,它僅僅起着佔位符的作用。

三、對象的訪問

Java 程序需要通過虛擬機棧上的 reference 數據來操作堆上的具體對象,reference 數據是一個指向對象的引用,不過如何通過這個引用定位到具體的對象,目前主要有以下兩種訪問方式:句柄訪問和直接指針訪問。

1、句柄訪問

句柄訪問會在 Java 堆中劃分一塊內存作爲句柄池,每一個句柄存放着到對象實例數據和對象類型數據的指針。

引用類型的變量存放的是該對象的句柄地址(reference)。訪問對象時,首先需要通過引用類型的變量找到該對象的句柄,然後根據句柄中對象的地址找到對象。優勢:對象移動的時候(這在垃圾回收時十分常見)只需改變句柄池中對象實例數據的指針,不需要修改reference本身。

句柄池訪問.png
句柄池訪問

2、直接指針訪問

直接指針訪問方式在 Java 堆對象的實例數據中存放了一個指向對象類型數據的指針,在 HotSpot 中,這個指針會被存放在對象頭中。但對象所在的內存空間需要額外的策略存儲對象所屬的類信息的地址。

優勢:減少了一次指針定位對象實例數據的開銷,速度更快。

直接指針訪問.png
直接指針訪問

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章