由於Java對象主要存放在Java堆裏,因此垃圾收集器(Garbage Collection)在對Java堆進行回收前,第一件事情就是要肯定這些對象之中哪些還「存活」着,哪些已經「死去」(不被引用了)。java
引用計數算法,很容易理解,在對象中添加一個引用計數器,每有一個地方引用它時,計數器值就加一;當引用失效是,計數器值就減一;任什麼時候刻計數器爲零的對象就是不能夠能再被使用的對象。
引用計數算法的原理簡單,斷定效率也很高。市面上也確實有一些技術使用的此類算法來斷定對象是否存活,像ActionScript 3 的FlashPlayer、Python語言等。可是在主流的Java虛擬機裏面都沒有選用引用計算法來管理內存,主要是使用此算法時,必需要配合大量的額外處理才能保證正確的工做,例如要解決對象之間的相互循環引用的問題。算法
public class OneTest { public Object oneTest = null; private static final int _1MB = 1024 * 1024; private byte[] bigSize = new byte[256 * _1MB]; /** * 這個成員屬性的惟一意義就是佔點內存,以便能在GC日誌中看清楚是否有回收過。 */ @Test public void testGC(){ OneTest test1 = new OneTest(); OneTest test2 = new OneTest(); test1.oneTest = test2; test2.oneTest = test1; test1 = null; test2 = null; // 假設在這行發生GC,test1和test2是否能被回收? System.gc(); } }
分析代碼,test1和test2對象都被設置成了null,在後面發生GC的時候,若是按照引用計數算法,這兩個對象雖然都被設置成了null,可是test1引用了test2,test2又引用了test1,因此這兩個對象的引用計數值都不爲0,因此都不會被回收,可是真正的實際運行結果是,這兩個對象都被回收了,這也說明HotSpot虛擬機並非用引用計數法來進行的內存管理。緩存
當前主流的商用程序語言(Java、C#等),都是經過可達性分析(Reachability Analysis)算法來判斷對象是否存活的。這個算法的基本思路就是經過一一系列稱爲「GC Roots」 的根對象做爲起始節點集,從這些節點開始根據引用關係向下搜索,搜索走過的的路徑稱爲「引用鏈」(Reference Chain),若是某個對象到GC Roots 間沒有任何引用鏈相連,或者從GC Roots 到這個對象不可達時,則證實此對象是不可能再被使用的。
以下圖,object十、object十一、object12這三個對象,雖然互相有關聯,可是它們到GC Roots是不可達的,所以它們會被斷定爲可回收的對象。
在Java程序中,固定可做爲GC Roots 的對象包括如下幾種:線程
不管是經過引用計數算法判斷對象的引用數量,仍是經過可達性分析算法判斷對象是否引用鏈可達,判斷對象是否存活都和「引用」離不開關係。在JDK1.2以前,Java裏對引用的概念是:若是reference類型的數據中存儲的數值表明的是另一塊兒內存的地址,就稱該reference數據是表明某塊內存、某個對象的引用。
在JDK1.2版以後,Java對引用的概念進行了擴充,將引用分爲強引用(Strongly Reference)、軟引用(Soft Reference)、弱引用(Weak Reference)、虛引用(Phantom Reference)4種,這4種引用強度依次逐漸減弱。設計
Object obj = new Object()
這種引用關係。不管在任何狀況下,只要強引用關係還存在,垃圾收集器就不會回收掉被引用的對象。日誌
即便在可達性分析算法中,判斷爲不可達的對象,也不是「非死不可」的,要真正宣告一個對象死亡,至少要經歷兩次標記過程:code
須要注意的是:任何一個對象的finalize()方法都只會被系統自動調用一次,若是對象面臨第二次回收,它的finalize()方法不會被再次執行。
還有一點就是Java官方已經明確聲明不推薦手動調用finalize()方法了,由於它的運行代價高昂,不肯定性大,沒法保證各個對象的調用順序,而且finanlize()能作的全部工做,使用try-finally或其餘方式均可以作的更好、更及時。對象
方法區垃圾收集的「性價比」一般比較低,而且方法區回收也有過於苛刻的斷定條件。
方法區的垃圾收集主要回收兩部份內容:廢棄的常量和再也不使用的類型,回收廢棄常量時,若是當前系統沒有一個常量的值是當前常量值,且虛擬機中也沒有其餘地方引用這個常量。若是這個時候發生垃圾回收,常量就會被系統清理出常量池。
斷定一個類型是否屬於「再也不使用的類」的條件就比較苛刻了,要同時知足以下三個條件:blog
同時知足了上述的三個條件後,也只是被容許進行回收了,關因而否要對類型進行回收還要對虛擬機進行一系列的參數設置,這裏就不贅述了,感興趣的能夠本身去查詢。隊列