JVM垃圾回收相關算法

基本回收算法
算法

在堆中幾乎保存着全部可以想到的對象實例,也就是根據對象存活的週期不一樣,將內存分爲不一樣的塊。安全

而目前的JVM中處理垃圾收集的方式--幾乎都採用的分代收集算法(即**將對象熬過垃圾收集的次數,視爲對象的年齡,也依此將對象至少劃分爲新生代和老年代這兩個代**)。數據結構

 

標記-清除算法

簡介:最基礎的收集算法是「標記-清除」(Mark-Sweep)算法,如其名,分爲「標記」和「清除」兩個階段:首先標記出全部須要回收的對象,在標記完成後統一回收全部被標記的對象;也能夠返回來標記存活的對象,統一回收沒有被標記的對象。後續算法都是基於這個優化改進的。ide

缺點:優化

  • 效率問題:若是須要標記的對象太多,或者清除的對象太多,效率都不高線程

  • 空間問題:標記清除後會產生大量不連續的內存碎片,空間碎片太多可能會致使之後分配較大對象時,沒法找到足夠的連續的內存而不得不提早觸發另外一次垃圾收集操做。3d

回收前:指針

img

回收後:對象

img

 

標記-複製算法

簡介:爲了解決效率問題,「複製」收集算法出現了。它將可用內存按容量劃分爲大小相等的兩塊,每次只使用其中的一塊。當這一塊的內存用完了,就將還存活的對象複製到另一塊上面,而後再把已使用過的內存空間一次清理掉。使得每次都是對整個半區進行內存回收,內存分配時也不用考慮內存碎片等複雜狀況,只要移動堆頂指針,按順序分配內存便可,運行高效。blog

缺點:

  • 直接將原有內存縮小爲了原來的一半,代價過高了。

  • 若是對象存活率較高時就要進行較多的複製操做,效率將會變低。

 

回收前:

img

回收後:

img

 

標記-整理算法

複製算法缺點就是對象存活率較高時,進行的複製操做多,效率低下,更關鍵的時浪費的50%的內存空間。若是不想浪費,就須要有額外的空間進行分配擔保,以應對被使用的內存中全部對象都100%存活的極端狀況,因此老年代通常不能直接選擇複製算法。

根據老年代的特色(對象存活率高,難於GC),出現了「標記-整理」算法。標記過程仍然與「標記-清除」算法同樣,但後續步驟中再也不直接對可回收對象進行清理,而是讓全部存活的對象都向一端移動,而後直接清理掉端邊界之外的內存。

回收前:

img

回收後:

img

分代收集算法

在新生代中,每次垃圾回收都會有大批對象死去,只有少數存活,那就選用複製算法,只要付出少許存活對象的複製成本就能夠完成收集。

而老年代中由於對象存活率高,沒有額外空間對它進行分配擔保,就必須使用「標記-清除」或者「標記-整理」算法來進行回收。

 

HotSpot算法實現

衆所周知,通常回收內存方法包括計數法、可達性分析法。可達性分析法即GC ROOTS(枚舉根結點,找到引用鏈)。

以此爲例,1.枚舉的節點主要存在於全局性的引用(如常量)與執行上下文(如棧幀的局部變量表)中,目前不少應用僅方法區就有數百兆,若是逐一檢查,一定消耗不少時間。2.另可達性分析對執行時間也很敏感,這就體如今GC的停頓上,由於分析工做必須在一個時間點上,不能夠出現分析過程當中,對象的引用關係還會發生變化的狀況,否則沒法保證準確性。這也是致使GC時必須停頓全部Java執行線程(STOP THE WORLD)的一個重要緣由。

 

隨即引出安全點的概念:

在HotSpot中,當執行系統停頓下來後,其會使用一組成爲OopMap的數據結構來記錄對象的引用,保存對象內什麼偏移量上是什麼類型的數據,以及特定位置記錄下棧和寄存器中有哪些位置是引用。這樣在GC掃描時,就能直接得知相關信息了。

在OopMap的協助下,HotSpot能夠快速準確地完成GC ROOTS枚舉,但隨着引用關係變化,或者OopMap內容變化的指令太多,若是爲每一條指令都生成OopMap指令,那就會須要大量的額外空間。

因此HotSpot也不可能爲每條指令都生成OopMap。只有在特定的位置纔會記錄下棧、寄存器信息,這些位置稱爲「安全點」(SafePoint),即程序執行時並不是在全部地方都停頓下來進行GC,只在安全點停頓。

SafePoint的選定既不能太少以致於讓GC等待時間太長,也不能太多致使GC過於頻繁,加大運行時的負荷。

因此,安全點的選擇基本上是以程序「是否具備讓程序長時間執行的特徵」爲標準進行選定的--由於每條指令執行的時間都很是短暫,程序不太可能由於指令流長度太長就過長時間運行。「長時間執行」的最明顯的特徵就是指令序列複用,例如:方法調用、循環跳轉、異常跳轉等(方法返回以前、調用某個方法以後、拋出異常的位置、循環的末尾)。

安全區域:savePoint是對正在執行的線程的設定。若是一個線程處於Sleep或中斷狀態,它就不能響應JVM的中斷請求,會卡住運行到savePoint上,由於JVM引入了safe Region。safe Region指的是一段代碼片斷中,引用關係不會發生變化,在這個區域內的任意地方開始GC都是安全的。

相關文章
相關標籤/搜索