物件的例項化、記憶體佈局以及訪問定位

保暖大褲衩LeoLee發表於2021-01-05

物件的例項化

建立物件的方式

  • new
    • 包括單例、xxxBuilder、xxxFactory等變形方式
  • 反射
    • Class物件的newInstance()方法,JDK9開始標識為廢棄(只能使用無參構造方法,訪問許可權為public)
    • Constructor的newInstance()方法(可以使用帶參構造方法,訪問許可權沒有限制)
  • clone:不使用構造方法,需要類實現Cloneable介面的clone()方法
  • 反序列化:從檔案或者網路中獲取一個物件的二進位制流

建立物件的步驟

  • 判斷物件對應的類是否載入、連結、初始化
    • JVM執行物件建立的時候(new物件),首先檢查這個指令的引數能否在Metaspace的常量池中定位到一個類的符號引用,並且檢查這個符號引用代表的類是否已經被載入、連結、初始化,即判斷類資訊是否在方法區中存在。如果沒有被載入,則要在雙親委派機制下,使用當前類載入器以Classloader+包名+類名為key來查詢class檔案,如果沒有找到相應的class檔案則丟擲ClassNotFoundException,如果找到就進行類載入,並生成相應的Class類物件。
  • 為物件分配記憶體首先計算物件佔用空間的大小,接著在堆中劃分一塊記憶體給新物件。如果例項中的成員變數是引用變數,僅分配引用變數空間即可,4個位元組大小
    • 分配空間的時候判斷記憶體是否規整(記憶體連續程度)
      • 如果是規整的記憶體,JVM將採用指標碰撞法(Bump The Pointer)來給物件分配記憶體
        • 所有用過的記憶體在一邊,空閒的空間在另一邊,中間放著一個指標作為分界點的指示器,分配記憶體就僅僅是把指標向空閒那邊挪動一段與物件大小相等的距離(一般使用帶有compact(整理)過程的收集器時,使用指標碰撞法,如垃圾收集器選擇的是Serial、ParNew這種基於壓縮演算法,JVM採用該分配方式)。
      • 如果記憶體不規整,JVM需要維護一個列表
        • 空閒列表分配法(Free list):記憶體不規整,已使用的記憶體和未使用的記憶體相互交錯,JVM維護一個列表記錄哪些記憶體塊是可用的,再分配的時候從列表中找出一塊足夠的大的空間劃分給物件,並更新列表記錄內容。
    • 具體使用以上哪種分配演算法,取決於Java堆中的記憶體規整程度,是否碎片化。記憶體的規整程度又取決於JVM垃圾收集器是否有壓縮整理功能來決定
  • 處理併發安全問題
    • 由於堆空間是共享的,多執行緒情況下會存在都去建立物件的安全問題。
      • 採用CAS失敗重試、區域加鎖保證更新的原子性
      • 每個執行緒預先分配一個TLAB區(JDK8預設開啟)
  • 初始化分配到的空間
    • 所有屬性設定預設值,保證物件例項欄位在不賦值的時候可以使用(如int預設值為0,String等引用物件預設為null)
  • 設定物件頭
    • 將物件的所屬類資訊、物件的HashCode和物件的GC資訊、鎖資訊等資料儲存在物件的物件頭中。這個過程的具體設定細節取決於JVM的具體實現
  • 執行<init>()方法進行初始化(顯式的初始化)
    • 實際從Java編碼角度來講,這才是顯而易見的初始化:初始化成員變數、執行例項化程式碼塊、呼叫類構造方法,並把堆內物件的首地址賦值給引用變數

物件的記憶體佈局

物件頭Header

  • 執行時後設資料(Mask word)
    • 雜湊值hashcode
    • GC分代年齡(物件的年齡計數器)、
    • 鎖狀態的標識
    • 執行緒池有的鎖
    • 偏向執行緒id
    • 偏向時間戳
  • 型別指標
    • 指向類後設資料,指明該物件的型別
  • 如果建立的是陣列還需要記錄資料的長度

例項資料Instance data

它是物件真正儲存的欄位有效資訊,包括程式程式碼中定義的各種型別的欄位(涵蓋父類繼承下來的和該類物件本身的)

規則:

  • 相同寬度的欄位總是被分配在一起
  • 父類定義的變數會出現在子類之前(現從父類開始載入嘛)
  • 如果CompactFields引數為true(預設為true),子類的窄變數可以放在父類變數的空隙

對齊填充Padding

沒有實際含義,起到佔位符的作用,可以增加CPU讀取的速率?

物件訪問定位

控制程式碼訪問

  • 區域性變數表中的引用物件指向了JVM堆中的控制程式碼
    • 控制程式碼包括兩個部分
      • 到物件例項資料的指標:指向JVM的物件例項資料
      • 到物件型別資料的指標:指向方法區的類資訊

直接訪問

區域性變數表中的引用物件直接指向了JVM堆中的物件例項,該物件例項又儲存了指向方法區的型別指標。Hotspot VM採用的是直接訪問


優缺點:

  • 控制程式碼訪問會多出一塊記憶體記錄控制程式碼資訊,訪問不如直接訪問
  • 控制程式碼訪問情況下,物件的移動只需要改變聚丙種指向物件例項資料的指標即可,無需改變區域性變數表中的引用。物件移動發生在例如標記整理演算法的時候,會發生物件記憶體地址的變化,物件的移動。物件在Survivor1和Survivor0中也是會發生互相移動的,在新生代的Eden區到Survivor區,或者晉升到老年代也是同理發生了物件的移動

 

 

 

相關文章