JVM GC的Heap

JVM的一個關鍵特徵是它的GC HeapHeap保存了Java運行期的所有對象,數組。GC可以動態釋放Heap中不再使用的空間。在Java程序裏,一個對象可以通過關鍵字new來創建,“創建”對於JVM來說就是在Heap裏分配一塊空間保存新對象。GC,也就是Garbage collection,既清除Heap裏不再使用的對象。爲了清除這些對象,GC必須調用這些對象的Finalizer。另爲GC還可以合併Heap中的空間碎片。Heap空間碎片是由於不斷分配和釋放造成的。如果不合並這些碎片,即使有足夠的空間,由於沒有足夠大的連續空間而不得不擴大Heap空間,擴大空間會降低運行性能。

GC算法

目前已經實現了很多GC算法,處理Sun之外,IBMSymantecMicrosoftHP,以及各種開源組織都投入到這項研究。那他們競爭的關鍵就在於GCHeap。任何一個GC算法都必須做兩件事,一,它必須能找到所有的垃圾對象,也就是不再使用的對象,二,它必須可以回收垃圾對象空間。

通常,搜索垃圾的工作,首先建立一組類似於樹的結構,樹根爲root,節點則叫做對象引用。任何一個對象如果在各種結構裏能找到它的引用,則成爲該對象可使用(reachable)或稱對象狀態是活動的(live),而任何沒有在結構裏找到引用的對象則稱爲垃圾。在JVM裏,所有的對象都保存在Heap裏,本地變量則保存在Java Stack裏,每個線程都有自己的Stack。每個本地變量或是對象引用,或是基本數據類型,例如int, charfloat。因此,線程裏保存的只是對象的引用,而對象的實例都保存在Heap中。當一個線程結束,線程裏對象引用將被刪除,那麼這些對象就有可能成爲Heap中的垃圾。(“有可能”是因爲對象有可能在其他線程中被引用。)

區別可使用對象和垃圾對象有兩種方法,他們是引用計數和遍歷搜索。引用計數就是在Heap中記錄各個對象的引用數。遍歷搜索是在樹結構裏搜索對象引用,並在Heap裏標記被引用的對象,遍歷後,那些沒有標記的對象則是垃圾。

引用計數器

引用計數器保存在對象裏,當一個對象被創建時,計數器爲1。當其他對象引用這個對象時,該對象的引用計數器加1。當對這個對象的引用結束時,計數器減1。引用計數器爲0時,則被看作是垃圾。該算法的缺點是沒有遍歷功能。該算法已經過時,現在的JVM都採用第二種方法遍歷搜索法。

遍歷搜索器

        搜索器從樹結構的根節點開始遍歷,尋找對象引用,並把被引用的對象做標記(Mark)。遍歷之後,未作標記的對象被視爲垃圾,可被GC回收(Sweep)。

碎片整理

        Heap碎片整理(Compacting collector)有兩個步驟,整理和拷貝。這兩步用來移動Heap中的對象從而減少碎片。既然好移動對象的位置,當要也要更新對象的引用,但是更新對象引用是會降低VM的性能,因此建立一個對象句柄表,對象引用指向對象句柄,當對象移動時,更新對象的句柄,而不用改變對象引用的值。拷貝步驟就是將Heap的對象移動到新的位置。爲了提高拷貝的性能,VM被分爲兩個區,VM在內只能使用兩個中的一個。當使用中的區沒有空間後,將所有的對象從該空間拷貝到另一個空間,並繼續在另一個空間工作,直到另一個空間滿了爲止,再把所有對象拷貝回原來的空間。該方法的代價就是需要花費2倍的空間。

 

 

 
發佈了96 篇原創文章 · 獲贊 8 · 訪問量 36萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章