在《Jvm垃圾回收器(基礎篇)》中咱們主要學習了判斷對象是否存活仍是死亡?兩種基礎的垃圾回收算法:引用計數法、可達性分析算法。以及Java引用的4種分類:強引用、軟引用、弱引用、虛引用。和方法區的回收介紹。html
那麼接下來咱們重點研究下虛擬機的幾種常見的垃圾回收算法:標記-清除算法、複製算法、標記-整理算法、分代收集算法。java
最基礎的收集算法,總共分爲‘ 標記 ’和‘ 清除 ’兩個階段算法
標記出全部須要回收的對象佈局
在《Jvm垃圾回收器(基礎篇)》中說明了判斷對象是否回收須要兩次標記,如今咱們再來回顧一下post
一次標記:在通過可達性分析算法後,對象沒有與GC Root相關的引用鏈,那麼則被第一次標記。而且進行一次篩選:當對象有必要執行finalize()方法時,則把該對象放入F-Queue隊列中。學習
二次標記:對F-Queue隊列中的對象進行二次標記。在執行finalize()方法時,若是對象從新與GC Root引用鏈上的任意對象創建了關聯,則把他移除出「 即將回收 」集合。不然就等着被回收吧!!!url
對被第一次標記切被第二次標記的,就能夠斷定位可回收對象了。spa
兩次標記後,還在「 即將回收 」集合的對象進行回收。.net
執行過程以下:代理
優勢:基礎最基礎的可達性算法,後續的收集算法都是基於這種思想實現的
缺點:標記和清除效率不高,產生大量不連續的內存碎片,致使建立大對象時找不到連續的空間,不得不提早觸發另外一次的垃圾回收。
將可用內存按容量分爲大小相等的兩塊,每次只使用其中一塊,當這一塊的內存用完了,就將還存活的對象複製到另一塊內存上,而後再把已使用過的內存空間一次清理掉。
複製算法執行過程以下:
優勢:實現簡單,效率高。解決了標記-清除算法致使的內存碎片問題。
缺點:代價太大,將內存縮小了一半。效率隨對象的存活率升高而下降。
如今的商業虛擬機都採用這種算法(須要改良1:1的缺點)來回收新生代。
分代垃圾收集基於弱代理論。具體描述以下:
其中IBM研究代表:新生代中98%的對象都是"朝生夕死"; 因此並不須要按1:1比例來劃份內存(解決了缺點1);
新生代內存分配一塊較大的Eden空間和兩塊較小的Survivor空間
每次使用Eden和其中一塊Survivor空間
回收時將Eden和Survivor空間中存活的對象一次性複製到另外一塊Survivor空間上
最後清理掉Eden和使用過的Survivor空間。
Hotspot虛擬機默認Eden和Survivor的大小比例是8:1。
若是另外一塊Survivor空間沒有足夠內存來存放上一次新生代收集下來的存活對象,那麼這些對象則直接經過擔保機制進入老年代。
關於分配擔保的內容,我會在講述垃圾收集器時詳細描述。
標記-整理算法是根據老年代的特色應運而生。
標記過程和標記-清理算法一致(也是基於可達性分析算法)。
和標記-清理不一樣的是,該算法不是針對可回收對象進行清理,而是根據存活對象進行整理。讓存活對象都向一端移動,而後直接清理掉邊界之外的內存。
標記-整理算法示意圖
優勢:不會像複製算法那樣隨着存活對象的升高而下降效率,不像標記-清除算法那樣產生不連續的內存碎片
缺點:效率問題,除了像標記-清除算法的標記過程外,還多了一步整理過程,效率更低。
當前商業虛擬機的垃圾收集都是採用「 分代收集 」算法。
根據對象存活週期的不一樣將內存劃分爲幾塊。通常把java堆分爲新生代和老年代。JVM根據各個年代的特色採用不一樣的收集算法。
新生代中,每次進行垃圾回收都會發現大量對象死去,只有少許存活,所以比較適合複製算法。只須要付出少許存活對象的複製成本就能夠完成收集。
老年代中,由於對象存活率較高,沒有額外的空間進行分配擔保,因此適合標記-清理、標記-整理算法來進行回收。
----對《深刻理解Java虛擬機》第3章垃圾收集器與內存分配策略 3.3小節總結。接下來總結3.5垃圾收集器。
參考:
《深刻理解Java虛擬機》
https://blog.csdn.net/tjiyu/article/details/53983064