原文地址:xeblog.cn/articles/23java
給對象中添加一個引用計數器,每當有一個地方引用這個對象的時候,計數器的值就加1;當對象的引用失效時,計數器的值就減1;任什麼時候刻計數器爲0的對象就被斷定爲可回收的對象。
存在兩個對象之間互相循環引用的問題算法
Object obj1 = obj2
Object obj2 = obj1
複製代碼
對象 obj1
引用了對象 obj2
,對象 obj2
又引用着對象 obj1
,兩個對象互相引用,使得計數器都不能爲0,這種狀況若是使用 引用計數法
就沒法判斷對象是不是可回收的。spa
經過一系列的稱爲 GC Roots
的對象做爲起始點,從這些節點開始向下搜索,搜索所走過的路徑稱爲 引用鏈
,當一個對象到 GC Roots
沒有任何 引用鏈
相連時,則證實此對象是可回收的。線程
如圖所示,對象 Object 五、Object 六、Object 7
雖然互相有關聯,可是它們到 GC Roots
是不可達的,因此它們將會被暫定爲是可回收的對象。但此時斷定並無徹底結束,由於斷定一個對象是不是可回收是須要通過兩次標記過程的,上述是第一次的標記過程,第二次標記則是將第一次標記的對象進行一次篩選:經過判斷該對象是否須要執行 finalize()
方法。若是該對象覆蓋了 finalize()
方法,而且系統沒有運行過該方法(finalize()
方法全局只運行一次),則表示該對象須要執行finalize()
方法,那麼這個對象將會被放入到一個叫 F-Queue
的隊列中,等待虛擬機中的一個低優先級的Finalizer
線程去執行它。在執行 finalize()
方法的過程當中,只要該對象沒有和 GC Roots
引用鏈上的任何一個對象有關聯,這個對象才能被真正的定爲是可回收的對象。指針
能夠做爲 GC Roots
的對象:code
JVM就是採用 可達性分析算法
來判斷對象是不是可回收的。cdn
方法區處於JVM的永久代區域,且永久代的垃圾回收效率遠低於堆中(尤爲是在新生代中)的回收效率,對於這塊區域主要是回收兩部份內容:廢棄常量和無用類。對象
回收常量與回收Java堆中的對象很是相似。若是當前系統中沒有任何一個變量與常量A相等,常量A也沒有在任何地方被引用,則常量A就是可回收的。blog
判斷一個類是否可回收是很是苛刻的,須要同時知足3個條件:隊列
ClassLoader
已經被回收;java.lang.Class
對象沒有在任何地方被引用,沒法在任何地方經過反射訪問該類的方法。首先經過 可達性分析算法
標記出全部須要回收的對象,在標記完成後統一回收全部被標記的對象。
缺點
將可用內存按容量分爲大小相等的兩塊,每次只使用其中的一塊,當這一塊內存用完時,就將還存活的對象複製到另一塊上,而後把已使用過的內存空間一次性清理掉。這樣使得每次都是對整個半區進行內存回收,內存分配時也就不用考慮內存碎片等複雜狀況,只要移動堆頂指針,按順序分配內存便可,簡單高效。
缺點
優勢
複製收集算法在對象存活率較高時就要進行較多的複製操做,效率將會變低,老年代通常不能直接選用這種算法。 根據老年代的特色,提出了一種「標記-整理」算法,標記過程與「標記-清除」算法同樣,不一樣的是這種算法不直接對可回收對象進行清理,而是讓全部存活的對象都向一端移動,而後直接清理掉端邊界之外的內存。
缺點
優勢
根據對象存活週期的不一樣,將 Java堆內存
劃分爲 新生代
和 老年代
,這樣能夠根據各個年代的特色採用最適當的回收算法。
新生代: 每次垃圾回收時都發現有大批對象死去,只有少許對象存活,可採用 複製算法
,只須要付出少許存活對象的複製成本就能夠完成回收。
老年代: 對象存活率高,沒有額外空間對它進行分配擔保,必須使用 標記-清除
或 標記-整理
算法進行回收。