「每日五分鐘,玩轉JVM」:對象從哪來
- 2019 年 10 月 3 日
- 筆記
面向對象
眾所周知,Java是一門面向對象的高級程式語言,那麼現在問題來了,對象從哪來呢?有些人會說通過new關鍵字來創建一個對象,說的很好,本篇我們就來解密在new一個對象的過程中,JVM都給我們做了什麼工作。
走哪來,到哪去
一個對象的誕生必定有一個類,通常我們都是通過new關鍵字實例化一個類來獲取該類的一個對象,類在載入的過程中會經歷一系列的檢查,解析,初始化等一系列的過程,我們會在後面詳細的分步驟進行講解,這裡我們只關心對象。
下面對象就要被載入到我們的虛擬機記憶體的堆記憶體中,載入到堆記憶體中也就意味著這個對象需要一定的空間,那麼這個空間走哪來呢?這裡JVM規範給出了兩種情況:
指針碰撞
所謂指針碰撞,前提的條件是JVM的堆記憶體是絕對工整的,中間有一個指針作為分割空閑空間和已用空間的」三八線「,指針碰撞一般發生在Eden區,跟蹤在Eden創建的最後一個對象,這個對象會被放在Eden的頂部。如果有足夠的空間,對象就會被創建在Eden,並且被放置在頂部,然後將指針向上移動(如果你玩過俄羅斯方塊,你就應該明白,說白了就是一種不可消除絕對規整的俄羅斯方塊),當俄羅斯方塊被堆滿之後,就會觸發一次Minor GC(關於GC的知識,我們在後面來講解)
打個比方來說,一個班裡有很多座位,學生必須按照順序來坐,這樣只需要知道最後一個進來的學生坐哪就知道下一個學生坐哪,以及有沒有空位~
在單執行緒的情況下,我們這樣使用是沒有什麼問題的,但是如果處於多執行緒並發的情況,就會出現分配空間失敗的情況,打個比方來說,就是把一個位置同時賣給了兩個人,這種情況勢必就會打架,這種情況下,我們可以採取兩種方法來解決這個問題:
- 使用CAS+失敗重試保證更新操作的原子性
CAS(Compare And Swap),關鍵是3個操作數。
記憶體值V
舊的預期值A
要修改的新值B
當且僅當預期值A和記憶體值V相同時,將記憶體值V修改為B,否則什麼都不做。
-
第二種方法,結合我們上節課說到的TLAB來實現,在分配記憶體的時候在每個執行緒上的TLAB(Thread Local Allocation Buffer)區域進行分配,這裡分配的時候可以初始化為零值,這一步操作保證了對象實例欄位在Java程式碼中不賦值就可以直接使用。
Free List
另一種情況是當堆記憶體不規整的情況下(學生不要排排坐),JVM會把沒來上課的學生(未使用的記憶體)記到小本本上,當有新學生(新的對象)來上課的時候,可以去看本本上的座點陣圖給學生安排座位~
這個JVM的小本本就叫做空閑列表(Free List)。
結語
到這裡,對於虛擬機,對象就已經找到了自己的座位並落座,下一篇,我們來介紹一下對象中都有什麼。