1. 程式人生 > >物件與記憶體_深入JVM(二)

物件與記憶體_深入JVM(二)

物件與記憶體

 

        簡要的瞭解一下虛擬機器中記憶體的使用細節,它們是如何建立、如何佈局、如何訪問的.

物件的建立

        (在java中,一個java類將會編譯成一個class檔案。在編譯時,java類並不知道引用類的實際記憶體地址,因此只能使用符號引用來代替。比如org.simple.People類引用org.simple.Tool類,在編譯時People類並不知道Tool類的實際記憶體地址,因此只能使用符號org.simple.Tool(假設)來表示Tool類的地址。而在類裝載器裝載People類時,此時可以通過虛擬機器獲取Tool類 的實際記憶體地址,因此便可以既將符號org.simple.Tool替換為Tool類的實際記憶體地址,及直接引用地址。)

        遇到一條new指令,首先先去 檢查 ,檢查這個指令的引數是否能在常量池中可以找到一個符號引用,並檢查這個符號引用已被載入過 .

        然後,虛擬機器將對這個新生物件分配記憶體 , 分配的記憶體大小在類載入後已經確定 .在堆中,不同區域記憶體分配的方式不同 , 兩種記憶體分配方式 : 1.指標碰撞(需要連續規整的記憶體,通過指標向空閒區域移動一段與物件大小相對等的距離) 2.空閒列表 (維護了一個記錄了記憶體使用狀態的列表,動態的維護列表, 分配記憶體時從列表中找到足夠大的空間劃分給物件,不需要記憶體連續和規整)

        由於堆是執行緒共享的區域,因此高併發情況下,一個指標移動的操作都會有執行緒安全問題 ,虛擬機器採用了 : 1.CAS+失敗重試的方式來保證分配記憶體操作時的原子性. 2.採用TLAB(本地執行緒分配緩衝)區域來分配記憶體, 用完並分配新的TLAB時,再進行同步加鎖操作,可保證原子性.

        記憶體分配完成後,虛擬機器會將分配空間(除物件頭區域)初始化為零值 , TLAB則在建立緩衝區域時將區域值清零,這也是為什麼我們可以直接使用new出來物件的各個屬性的值的原因.

        接下來,虛擬機器將初始化物件頭區域 , 將類的元資料,物件的雜湊碼,物件的GC分代年齡等資訊,已規定格式,寫入物件頭區域.

物件的佈局

                物件在記憶體中的儲存佈局可以分為3塊區域 : 物件頭 , 例項資料 和對其填充.

        物件頭

                HotSpot虛擬機器記憶體頭包括兩部分資訊 : 1.儲存物件自身的執行時資料,官方稱為"Mark Word",這一部分儲存了HashCode,GC分代年齡,鎖狀態標誌,執行緒持有的鎖,偏向執行緒ID,偏向時間戳等...

                2.型別指標,指向該物件的類元資料的指標,如果該物件是一個數組,那麼在物件頭中還有記錄陣列長度的資訊

        例項資料

                是用來儲存物件資訊的有效資料區,即各欄位的值 ,無論是定義的還是繼承的欄位,資訊都會在這個區域 . 各欄位資訊在該區域的排列順序受分配策略影響(父類變數在前,相同寬度的資料型別會排列在一起...)

        填充資料

                物件的總大小必須是8位元組的倍數,例項資料區不足8位元組的,要求填充到8位元組.

物件的訪問定位

 

 

 

 

                HotSpot是使用直接指標來訪問物件的.