JVM-2 對象的創建與對象的定位

對象的創建流程

當我們new了一個對象的時候,JVM是如何操作,使這個對象可用的呢?
對象創建流程

  • 加載檢查
    虛擬機遇到一條new指令時,首先去檢查這個參數是否能在常量池中定位到一個類的符號引用,並且檢查這個符號引用是否已被加載、解析和初始化過。如果沒有,那必須先進行相應的類加載過程。

  • 分配內存
    對象所需內存的大小在加載完成後便可完全確定,這個過程主要是在堆中劃分出一塊內存來存儲對象,內存分配有兩種方式:
    指針碰撞 :用於經過垃圾回收後,Java堆絕對規整的內存區域,例如複製算法(Serial、ParNew、Parallel Scavenge)和標記整理算法(Serial Old、Parallel Old)。指針碰撞分配內存僅僅是把分隔已用空間和空閒內存的指針向空閒空間那邊挪動一段與對象大小相等的距離。
    空閒列表:用於經過垃圾回收後,Java堆不是規整的情況,例如CMS這種基於Mark-Sweep算法的垃圾收集器。空間列表法虛擬機必須維護一個列表,記錄哪些內存塊是可用的,在分配的時候找到一塊足夠大的空間分配個對象,並更新表上的記錄。

    分配內存過程中的線程安全

    • CAS : 虛擬機採用CAS配上失敗重試的方案保證指針移動過程中的原子性。
    • TLAB(本地線程分配緩衝):給每個線程在Java堆中預先分配一小塊內存,稱爲TLAB。哪個線程要分配內存,就在哪個線程的TLAB上分配,只有TLAB用完需要重新分配時,才需要同步鎖定。 啓用TLAB,通過-XX:+/-UseTLAB來設定。
  • 初始化
    1.類實例變量初始化:分配完內存空間後需要將對象的實例字段初始化爲默認值,如果使用TLAB,這一過程也提前至TLAB分配時進行。
    2.類的常量的初始化:類的常量在編譯階段就會爲其生成ConstantValue屬性,並在類加載階段的準備階段分配內存空間的同時賦值。
    3.類的靜態變量的初始化:準備階段後,類靜態變量跟實例變量一樣,保持默認值,在類構造器<client>方法執行時,進行初始化賦值操作。

對象的訪問定位

句柄

在這裏插入圖片描述
使用句柄訪問的話,Java堆會劃分出一塊內存來作爲句柄池,reference中存儲的是對象的句柄地址,句柄中包含了對象實例數據與類型數據各自的具體地址信息。好處是reference存儲的是穩定的句柄地址,對象被移動時只會改變句柄中的實例數據指針,而reference本身不需要修改;壞處是增加一次指針定位的時間開銷,速度比較慢。

直接指針

在這裏插入圖片描述
HotSpot JVM採用的對象訪問方式。直接指針訪問,reference中存儲的是對象地址,類型數據地址存在對象中。好處速度快,節省了一次指針定位的開銷。

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