Java垃圾回收機制與典型的垃圾回收演算法
說到垃圾回收(Garbage Collection,GC),很多人就會自然而然地把它和Java聯絡起來。在Java中,程式設計師不需要去關心記憶體動態分配和垃圾回收的問題,這一切都交給了JVM來處理。顧名思義,垃圾回收就是釋放垃圾佔用的空間,那麼在Java中,什麼樣的物件會被認定為“垃圾”?那麼當一些物件被確定為垃圾之後,採用什麼樣的策略來進行回收(釋放空間)?在目前的商業虛擬機器中,有哪些典型的垃圾收集器?下面我們就來逐一探討這些問題。以下是本文的目錄大綱:
一.如何確定某個物件是“垃圾”?
二.典型的垃圾收集演算法
三.典型的垃圾收集器
如果有不正之處,希望諒解和批評指正,不勝感激。
請尊重作者勞動成果,轉載請標明原文連結:
一.如何確定某個物件是“垃圾”?
在這一小節我們先了解一個最基本的問題:如果確定某個物件是“垃圾”?既然垃圾收集器的任務是回收垃圾物件所佔的空間供新的物件使用,那麼垃圾收集器如何確定某個物件是“垃圾”?—即通過什麼方法判斷一個物件可以被回收了。
在java中是通過引用來和物件進行關聯的,也就是說如果要操作物件,必須通過引用來進行。那麼很顯然一個簡單的辦法就是通過引用計數來判斷一個物件是否可以被回收。不失一般性,如果一個物件沒有任何引用與之關聯,則說明該物件基本不太可能在其他地方被使用到,那麼這個物件就成為可被回收的物件了。這種方式成為引用計數法
這種方式的特點是實現簡單,而且效率較高,但是它無法解決迴圈引用的問題,因此在Java中並沒有採用這種方式(Python採用的是引用計數法)。看下面這段程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public class Main
{
public static void main(String[]
args) {
MyObject
object1 = new MyObject(); MyObject
object2 = new MyObject();
object1.object
= object2;
object2.object
= object1;
object1
= null ;
object2
= null ;
}
}
class MyObject{
public Object
object = null ;
}
|
最後面兩句將object1和object2賦值為null,也就是說object1和object2指向的物件已經不可能再被訪問,但是由於它們互相引用對方,導致它們的引用計數都不為0,那麼垃圾收集器就永遠不會回收它們。
為了解決這個問題,在Java中採取了 可達性分析法。該方法的基本思想是通過一系列的“GC Roots”物件作為起點進行搜尋,如果在“GC Roots”和一個物件之間沒有可達路徑,則稱該物件是不可達的,不過要注意的是被判定為不可達的物件不一定就會成為可回收物件。被判定為不可達的物件要成為可回收物件必須至少經歷兩次標記過程,如果在這兩次標記過程中仍然沒有逃脫成為可回收物件的可能性,則基本上就真的成為可回收物件了。
至於可達性分析法具體是如何操作的我暫時也沒有看得很明白,如果有哪位朋友比較清楚的話請不吝指教。
下面來看個例子:
1 2 3 4 5 6 7 |
Object
aobj = new Object
( ) ;
Object
bobj = new Object
( ) ;
Object
cobj = new Object
( ) ;
aobj
= bobj;
aobj
= cobj;
cobj
= null ;
aobj
= null ;
|
第幾行有可能會使得某個物件成為可回收物件?第7行的程式碼會導致有物件會成為可回收物件。至於為什麼留給讀者自己思考。
再看一個例子: