Java對象的實例化過程


對象的創建

  1. 檢查對象對應的類是否已被虛擬機加載

    當虛擬機遇到new對應的字節碼指令時,首先檢查這個指令的參數是否能在常量池中找到一個類的符號引用,並檢查該引用代表的類是否已被虛擬機加載、解析和初始化。如果沒有則執行相應的類加載過程。

  2. 虛擬機為新生對象分配內存(對象所需的內存大小在類加載的過程中已經確定)

    內存分配有兩種方式:

    🌳指針碰撞:假設Java堆中的內存是規整有序的。已用的內存聚集在一塊,空閑的內存聚集在另一塊。使用一個指針指向兩塊區域中間,那么需要分配的內存就僅僅把這個指針向空閑區域移動當前對象大小的距離。

    🌳空閑列表:如果Java堆內存是已用和空閑交錯在一塊,並且維護一個列表記錄內存的使用情況。當需要分配一定大小的存儲時,通過查詢列表來獲取存儲空間。

    選擇哪種分配方式由Java堆內存是否規整決定,而Java堆內存是否規整由取決於垃圾收集器是否帶有壓縮的功能。

  3. 線程安全問題

    由於對象的創建在虛擬機中是一個頻繁的行為,可能會引起非線程安全問題。解決方法有兩種:

    🌴對分配內存空間的動作進行同步處理——采用CAS(比較再交換)配上失敗重試的方法保證更新操作的原子性

    🌴把內存分配的動作按照線程划分在不同的空間進行——每個線程預先分配一塊內存(本地線程分配緩沖區TLAB),哪個線程要分配內存就在哪個TLAB中分配。當TLAB用完了,分配新的緩沖區時才需要同步鎖定。

  4. 分配的內存空間初始化

    內存空間分配完成后,虛擬機必須對分配好的內存空間(不包括對象頭)都進初始化為零值。這一步操作保證了對象的實例字段在Java代碼中可以不用賦值直接使用。

  5. 設置對象頭。

    將對象的所屬類(即類的元數據信息)、對象的HashCode和對象的GC信息、鎖信息等數據存放在對象的對象頭中。

  6. 執行<init>()方法進行初始化。

    <init>()方法包含了初始化成員變量、執行實例化代碼塊和調用類的構造方法:

    image-20200823192337299

對象的內存布局

對象在堆內存中的存儲布局可以划分為三部分:

  1. 對象頭

    🌲​ 對象頭包含兩部分數據:

    • 運行時元數據:HashCode、對象年齡、鎖狀態標志、線程持有的鎖等信息;
    • 類型指針:指向類元數據,確定對象所屬的類型。(並不是所有的對象都要存儲類型指針)

    如果對象是數組,則還需記錄數組的長度。

  2. 實例數據

    即類中定義的各種類型屬性(包括從父類繼承下來的和本身定義的)。實例數據存放具有一定規則:相同寬度的字段總是被分配在一起;父類中定義的變量會出現在子類之前。

  3. 對齊填充:不是必須的,也沒有特殊含義,起到占位符的作用。

下面通過一個例子來演示對象的內存布局。現有如下代碼:

public class Customer {

    int id = 100;
    String name;
    Account account;	

    {
        name = "大客戶";
    }

    public Customer() {
        account = new Account();
    }

    public static void main(String[] args) {
        Customer customer = new Customer();
    }

}

class Account {

}

main方法創建Customer對象后,相關內存布局如下圖所示:

image-20200823193320822

對象的訪問定位

創建對象是為了后續使用該對象。Java程序會通過Java棧上的reference數據來操作Java堆上的具體對象。

主流虛擬機的訪問方式有:

句柄訪問:Java堆中將會划分出一塊內存來作為句柄池,reference中存儲的就是對象的句柄地址,而句柄中包含了對象實例數據類型數據各自具體的地址信息👇

image-20200823201937274

直接指針訪問:reference中存儲的直接就是對象在Java堆中的地址,該對象的內存布局必須考慮放至訪問類型數據的相關信息👇

image-20200823202511822

兩種對象的訪問方式各有優點:

🍁 對於句柄訪問方式,reference存儲的是句柄地址,當對象在內存中被移動時,只需要改變句柄中實例數據的指針,而reference本身不需要改變。

🍁 直接指針訪問的最大優點就是訪問速度很快。

本文參考:https://mrbird.cc/Java對象實例化過程.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM