在前面我們了解了虛擬機器如何判斷物件可**,接下來我們了解j**a虛擬機器垃圾收集的一些理論和演算法。
分代收集理論,是基於程式執行物件存活數量和物件年齡之間關係的一套經驗法則。
它建立在兩個分代假說之上:
用通俗的話總結:大部分汙漬很容易擦乾淨,多次擦都沒擦乾淨的無責越來越難擦乾淨。
基於這個理論,收集器將j**a堆劃分出不同的區域,然後將**物件按照年齡分配到不同的區域儲存。
具體來講,就是把j**a堆劃分為新生代 (young generation)和老年代(old generation)兩個區域,新生代存放存活時間短的物件,而每次**後存活的少量物件,將會逐步晉公升到老年代中存放。
對於新生代的物件,可以只關注如何保留少量存活而不是去標記那些大量將要被**的物件;
對於老年代,可以降低垃圾收集頻率,同時更加關注那些要消亡的物件。
為了降低垃圾**的代價,在新生代和老年代採用了不同的垃圾收集演算法。
基於分代,產生了一些垃圾收集的型別劃分:見名知義,整堆收集(full gc):收集整個j**a堆和方法區的垃圾收集。
標記-清除
(mark-sweep)演算法分為兩個階段:
標記-清除演算法比較基礎,但是主要存在兩個缺點:
標記-清除演算法主要用於老年代,因為老年代可**的物件比較少。
標記-複製演算法解決了標記-清除演算法面對大量可**物件時執行效率低的問題。
過程也比較簡單:將可用記憶體按容量劃分為大小相等的兩塊,每次只使用其中的一塊。當這一塊的記憶體用完了,就將還存活著的物件複製到另外一塊上面,然後再把已使用過的記憶體空間一次清理掉。
這種演算法存在乙個明顯的缺點:一部分空間沒有使用,存在空間的浪費。
新生代垃圾收集主要採用這種演算法,因為新生代的存活物件比較少,每次複製的只是少量的存活物件。
一般虛擬機器的具體實現不會採用1:1的比例劃分,以hotspot為例,hotspot虛擬機器將記憶體分為一塊較大的eden空間和兩塊較小的 survivor空間,每次分配記憶體只使用eden和其中一塊survivor。發生垃圾蒐集時,將eden和survivor中仍然存活的物件一次性複製到另外一塊survivor空間上,然後直接清理掉eden和已用過的那塊survivor空間。預設eden和survivor的大小比例是8∶1。
其中的標記過程仍然與「標記-清除」演算法一樣,但後續步驟不是直接對可**物件進行清理,而是讓所有存活的物件都向記憶體空間一端移動,然後直接清理掉邊界以外的記憶體。
標記-整理演算法主要用於老年代,在老年代這種大量物件存活的區域,移動物件是個很大的負擔,而且這種物件移動操作必須全程暫停使用者應用程式(stop the world)才能進行。
參考:
:周志朋編著《深入理解j**a虛擬機器:jvm高階特性與最佳實踐》
:j**a 虛擬機器系列二:垃圾收集機制詳解,**幫你理解
:極客時間《深入拆解j**a虛擬機器》
JVM 垃圾收集
1.引用計算法 給物件新增乙個引用計數器,每當有乙個地方引用它時,計數器值加一,當引用失效時,計數器值減一。當該物件的計數器值為0時,表明該物件不可用,虛擬機器可以對其進行 但是不能解決迴圈引用問題。2.可達性分析演算法 演算法思想為 以一系列的gc roots作為起點進行搜尋,搜尋走過的路徑稱之為...
JVM 垃圾收集演算法
這裡只是各個演算法的思想及發展過程 這是最基礎的收集演算法,分為兩個過程,標記和清除兩個階段。首先標記出需要 的物件,在標記完成後統一 掉所有被標記的物件。標記的過程就是之前判定物件的時候標記的。後續的演算法都是基於這種思路進行改進的。缺點呢,有兩個,1.效率問題,標記和清除的效率都不高。2.空間問...
JVM之垃圾收集演算法
標記清除演算法主要分為兩個階段,標記階段和清除階段,這兩個階段效率比較低,而且收集之後會產生記憶體碎片,無法為大的物件分配記憶體空間。如下圖 複製演算法解決了記憶體碎片問題,但是隨之而來的卻是把記憶體一分為二。原理是 記憶體一分為二,每次使用其中的一半,當需要 的時候,講死亡物件清理,然後存活物件移...