JAVA中對象的創建、對象的內存佈局、對象的訪問定位

        對象的創建:在語言層面,創建對象通常僅僅需要一個new關鍵字即可創建一個對象。而在虛擬機中,對象的創建是一個複雜的過程。當JVM遇到一個new指令的時候,首先將去檢查這個指令的參數能否在常量池中找到 一個類的符號引用,並且檢查這個符號引用所代表的類是否已經被加載、解析、初始化過。如果沒有,將先進行類加載的過程。在類加載檢查通過後,虛擬機就要爲新生對象分配內存,所需內存的大小在類加載完成後便可以完全確定,爲對象分配空間的任務等同於把一塊確定大小的內存從Java堆中劃分出來。爲對象分配內存的兩種方式:1、指針碰撞:假設Java堆中的對象是絕對規整的,所有用過的放一邊,沒用過的放另一邊,中間有一個指針作爲一個分界的指示器,那所分配內存就僅僅是把那個指針向空閒空間那邊挪動一段與對象大小相等的距離,這種分配方式稱爲“指針碰撞”。2、空閒列表:如果Java堆中的內存並不是規整的,已使用的內存和未使用的內存相互相錯,這時就沒辦法用指針碰撞的方式,這時虛擬機就必須維護一個列表,用以記錄哪些內存塊是可用的,在分配的時候從列表中找出一塊足夠大的空間劃分給對象實例,並更新列表上的記錄,這種分配方式稱爲“空閒列表”。

       除如何劃分可用空間之外,還有另外一個需要考慮的問題是對象創建在虛擬機中是非常頻繁的行爲,即使是緊緊修改一個指針所指向的位置,在併發情況下也並不是線程安全的,可能出現正在給對象A分配內存,指針還沒來得及修改,對象B又同時使用了原來的指針來分配內存的情況。解決這個問題有兩個方案,一種是對分配內存空間的動作進行同步處理-實際上虛擬機採用CAS配上失敗重試的方法保證更新操作原子性;另一種是把內存分配的動作按照線程劃分在不同的空間之中進行,即每個線程在Java堆中預先分配一小塊內存,稱爲本地線程分配緩衝(Thread local Allocation Buffer,TLAB)。哪個線程需要分配內存,就在哪個線程的TLAB上分配,只有TLAB用完並分配新的TLAB時,才需要同步鎖定。虛擬機是否使用TLAB,可以通過-XX:+/-UseTLAB參數來設定。

       內存分配完成後,虛擬機需要把分配到的內存空間都初始化爲0值(不包括對象頭)。然後對對象進行必要的設置(放在對象頭中,如這個對象是哪個類的實例,如何才能找到對象的元數據信息、對象的哈希碼、對象的GC分代年齡等信息)。上述工作完成後,從虛擬機的角度一個對象已經產生,但從程序的角度未結束,因爲在內存分配完成後,虛擬機把分配到的內存空間都初始化爲0,還未對對象根據程序員的意願進行初始化,因此會繼續執行初始化方法,初始化結束,一個真正的對象產生了。

       HotSpo虛擬機中,對象的內存佈局:對象在內存中存儲的佈局可以分爲3塊:對象頭、實例數據、對齊填充

       1、對象頭分爲兩個部分:第一部分用於存儲對象自身的運行時數據,如哈希碼、GC分代年齡、鎖狀態標誌等等。第二部分是類型指針,即對象指向它的類元數據的指針,虛擬機通過這個指針來確定對象是哪個類的實例。如果對象是數組,那麼對象頭中必須還有一塊用於記錄數組長度的數據。

       2、實例數據:對象真正存儲的有效信息,也是在程序代碼中所定義的各種類型的字段內容。無論是從父類中繼承的,還是在子類定義的,都要記錄起來。父類定義的變量會出現在子類之前。這部分的存儲順序會受到虛擬機分配策略參數和字段在Java源碼中定義的順序影響。HotSpot虛擬機默認的分配策略爲longs/double、ints、shorts/chars、bytes/booleans、oops,從分配策略中可以看出,相同寬度的字段總是被分配到一起。在滿足這個前提條件下,在父類中出現的變量會出現在子類之前。

       3、對齊填充:並不是必然存在的,僅僅起到佔位符的作用。由於虛擬機(例如HotSpot VM)的自動內存管理系統要求對象起始地址必須是8字節的整數倍,因此對象的大小必須是8的整數倍。

       對象的訪問定位:創建對象是爲了使用它,那麼Java程序如何通過棧上的引用來找到堆上的對象?目前兩種主流的方式分別是使用句柄和直接指針兩種。

       1、使用句柄來訪問:JAVA中劃分一塊內存作爲句柄池,棧中存放的引用就是對象的句柄地址,而句柄中包含了對象實例數據與類型數據各自的具體地址信息。

       2、直接指針:引用存放的直接就是對象地址。

       以上兩種方法各有優缺點:使用句柄的好處就是引用中存儲的是穩定的句柄地址,在對象被移動時(GC收集時會經常移動對象)只會改變句柄中實例數據指針,而引用本身不需要變化。指針訪問的最大好處就是快,節約了一次指針定位的時間開銷。主要的虛擬機Sun HotSpot採用的就是指針訪問。

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