在說垃圾回收算法之前,先談談JVM怎樣確定哪些對象是“垃圾”。
1.引用計數器算法:引用計數器算法是給每個對象設置一個計數器,當有地方引用這個對象的時候,計數器+1,當引用失效的時候,計數器-1,當計數器為0的時候,JVM就認為對象不再被使用,是“垃圾”了。
引用計數器實現簡單,效率高;但是不能解決循環引用問問題(A對象引用B對象,B對象又引用A對象,但是A,B對象已不被任何其他對象引用),同時每次計數器的增加和減少都帶來了很多額外的開銷,所以在JDK1.1之后,這個算法已經不再使用了。
2.根搜索方法:根搜索方法是通過一些“GCRoots”對象作為起點,從這些節點開始往下搜索,搜索通過的路徑成為引用鏈(ReferenceChain),當一個對象沒有被GCRoots的引用鏈連接的時候,說明這個對象是不可用的。
GCRoots對象包括:
a)虛擬機棧(棧幀中的本地變量表)中的引用的對象。
b)方法區域中的類靜態屬性引用的對象。
c)方法區域中常量引用的對象。
d)本地方法棧中JNI(Native方法)的引用的對象。
了解了JVM是怎么確定對象是“垃圾”之后,進入正題,讓我們來看看垃圾回收的算法。
1.標記—清除算法(Mark-Sweep)標記—清除算法包括兩個階段:“標記”和“清除”。在標記階段,確定所有要回收的對象,并做標記。清除階段緊隨標記階段,將標記階段確定不可用的對象清除。
標記—清除算法是基礎的收集算法,標記和清除階段的效率不高,而且清除后回產生大量的不連續空間,這樣當程序需要分配大內存對象時,可能無法找到足夠的連續空間。
垃圾回收前:

垃圾回收后:

綠色:存活對象紅色:可回收對象白色:未使用空間
2.復制算法(Copying)復制算法是把內存分成大小相等的兩塊,每次使用其中一塊,當垃圾回收的時候,把存活的對象復制到另一塊上,然后把這塊內存整個清理掉。
復制算法實現簡單,運行效率高,但是由于每次只能使用其中的一半,造成內存的利用率不高。現在的JVM用復制方法收集新生代,由于新生代中大部分對象(98%)都是朝生夕死的,所以兩塊內存的比例不是1:1(大概是8:1)。
垃圾回收前:

垃圾回收后:

綠色:存活對象紅色:可回收對象白色:未使用空間
3.標記—整理算法(Mark-Compact)標記—整理算法和標記—清除算法一樣,但是標記—整理算法不是把存活對象復制到另一塊內存,而是把存活對象往內存的一端移動,然后直接回收邊界以外的內存。
標記—整理算法提高了內存的利用率,并且它適合在收集對象存活時間較長的老年代。
垃圾回收前:

垃圾回收后:

綠色:存活對象紅色:可回收對象白色:未使用空間
4.分代收集(GenerationalCollection)分代收集是根據對象的存活時間把內存分為新生代和老年代,根據個代對象的存活特點,每個代采用不同的垃圾回收算法。新生代采用標記—復制算法,老年代采用標記—整理算法。
垃圾算法的實現涉及大量的程序細節,而且不同的虛擬機平臺實現的方法也各不相同。上面介紹的只不過是基本思想。
文章轉自:http://blog.csdn.net/ol_beta/article/details/6791229
新聞熱點
疑難解答