1. 程式人生 > >Java物件建立過程

Java物件建立過程

物件的建立過程

物件的建立

當虛擬機器遇到一條new指令時,首先將去檢查這個指令的引數是否能在常量池中定位到某個類的符號引用,並且檢查這個符號引用代表的類是否已被載入、解析、初始化。

物件記憶體的分配

如果沒有,則必須先執行相應的類載入過程,當類載入檢查通過後,虛擬機器將為新生物件分配記憶體,物件所需記憶體的大小在類載入完成後便可完全確定,為物件分配空間的任務等同於把一塊確定大小的記憶體從Java堆劃分出來

若Java堆中記憶體是絕對完整的,所有用過的記憶體都放在一邊,空閒的記憶體都放在一邊,中間放著一個指標作為分界點的指示器,那所分配記憶體就僅僅是把那個指標想空閒空間挪動一段與物件大小相等的距離(指標碰撞)

若Java堆記憶體並不規整,已使用的記憶體和空閒的記憶體相互交錯,虛擬機器必須維護一個列表,記錄哪些記憶體塊是可用的,在分配的時候從列表中找到一塊足夠大的空間劃分給物件例項,並更新列表上的記錄(空閒列表)

選擇哪種分配方式由Java堆是否規整決定,而Java堆是否規整又由所採用的垃圾收集器是否帶有壓縮整理功能決定。

物件在虛擬機器中的建立是一個非常頻繁地行為,即使僅僅修改一個指標所指向的位置,在併發的情況下並不是執行緒安全的(虛擬機器正在為物件A分配記憶體,指正還沒來得及修改,物件B又同時使用了原來的指標來分配記憶體的情況)。

兩種方式解決以上情況

  1. 分配記憶體空間的動作進行同步處理------虛擬機器採用CAS(比較交換演算法
    ) + 失敗重試 來保證更新操作的原子性
  2. 把記憶體分配的動作按照執行緒劃分在不同的空間之中進行,每個執行緒在Java堆中預先分配一小塊記憶體(本地執行緒分配緩衝 TLAB),哪個執行緒要分配記憶體,就在哪個執行緒的TLAB上分配,只有TLAB用完並分配新的TLAB時,才需要同步鎖定,虛擬機器是否使用分配緩衝,通過-XX:+/-UserTLAB引數設定。

記憶體分配完成以後,虛擬機器需要將分配到的記憶體空間都初始化為零值(不包括物件頭)如果使用TLAB,這一工作過程也可以提前至TLAB分配時進行。這一步操作保證了物件的例項欄位在Java程式碼中可以不賦初始值就可以直接使用,程式訪問到這些欄位的資料型別所對應的零值。

記憶體分配完成以後,虛擬機器需要為物件配置資訊(哪個類的例項、如何才能找到類的元資料資訊物件的雜湊碼物件的GC分帶年齡),這些資訊存放在物件的物件頭之中。根據虛擬機器當前的執行狀態的不同,物件頭會有不同的設定方式。

物件的生命由Java虛擬機器賦予,而物件的屬性和行為由Java程式來分配,即虛擬機器在堆記憶體空間為新的物件分配記憶體空間後,還需執行<init>方法來初始化物件的欄位,最終以程式設計師的意願完成物件的初始化,這樣,物件才具有真正的使用價值。

物件的建立過程

當虛擬機器遇到一條new指令時,首先將去檢查這個指令的引數是否能在常量池中定位到某個類的符號引用,並且檢查這個符號引用代表的類是否已被載入、解析、初始化。

如果沒有,則必須先執行相應的類載入過程,當類載入檢查通過後,虛擬機器將為新生物件分配記憶體,物件所需記憶體的大小在類載入完成後便可完全確定,為物件分配空間的任務等同於把一塊確定大小的記憶體從Java堆劃分出來

若Java堆中記憶體是絕對完整的,所有用過的記憶體都放在一邊,空閒的記憶體都放在一邊,中間放著一個指標作為分界點的指示器,那所分配記憶體就僅僅是把那個指標想空閒空間挪動一段與物件大小相等的距離(指標碰撞)

若Java堆記憶體並不規整,已使用的記憶體和空閒的記憶體相互交錯,虛擬機器必須維護一個列表,記錄哪些記憶體塊是可用的,在分配的時候從列表中找到一塊足夠大的空間劃分給物件例項,並更新列表上的記錄(空閒列表)

選擇哪種分配方式由Java堆是否規整決定,而Java堆是否規整又由所採用的垃圾收集器是否帶有壓縮整理功能決定。

物件在虛擬機器中的建立是一個非常頻繁地行為,即使僅僅修改一個指標所指向的位置,在併發的情況下並不是執行緒安全的(虛擬機器正在為物件A分配記憶體,指正還沒來得及修改,物件B又同時使用了原來的指標來分配記憶體的情況)。

兩種方式解決以上情況

  1. 分配記憶體空間的動作進行同步處理------虛擬機器採用CAS(比較交換演算法) + 失敗重試 來保證更新操作的原子性
  2. 把記憶體分配的動作按照執行緒劃分在不同的空間之中進行,每個執行緒在Java堆中預先分配一小塊記憶體(本地執行緒分配緩衝 TLAB),哪個執行緒要分配記憶體,就在哪個執行緒的TLAB上分配,只有TLAB用完並分配新的TLAB時,才需要同步鎖定,虛擬機器是否使用分配緩衝,通過-XX:+/-UserTLAB引數設定。

記憶體分配完成以後,虛擬機器需要將分配到的記憶體空間都初始化為零值(不包括物件頭)如果使用TLAB,這一工作過程也可以提前至TLAB分配時進行。這一步操作保證了物件的例項欄位在Java程式碼中可以不賦初始值就可以直接使用,程式訪問到這些欄位的資料型別所對應的零值。

記憶體分配完成以後,虛擬機器需要為物件配置資訊(哪個類的例項、如何才能找到類的元資料資訊物件的雜湊碼物件的GC分帶年齡),這些資訊存放在物件的物件頭之中。根據虛擬機器當前的執行狀態的不同,物件頭會有不同的設定方式。

物件的生命由Java虛擬機器賦予,而物件的屬性和行為由Java程式來分配,即虛擬機器在堆記憶體空間為新的物件分配記憶體空間後,還需執行<init>方法來初始化物件的欄位,最終以程式設計師的意願完成物件的初始化,這樣,物件才具有真正的使用價值。