怎麼肯定對象已經死了?java
怎麼肯定對象已經死了?怎麼肯定一個對象已經死了?算法
給對象中添加一個引用計數器,每當有個地方引用它,計數器值就加1,引用失效,計數器減1,任什麼時候刻計數器爲0的對象就不能再應用了。ide
很難解決對象之間的相互循環引用。oop
引用計數收集器能夠很快的執行,而且交織在程序運行中,對程序須要不被長時間打斷的實時環境比較有利,但其很難解決對象之間相互循環引用的問題。以下面的程序和示意圖所示,對象objA和objB之間的引用計數永遠不可能爲 0,那麼這兩個對象就永遠不能被回收。this
public class ReferenceCountingGC { public Object instance = null; public static void testGC(){ ReferenceCountingGC objA = new ReferenceCountingGC (); ReferenceCountingGC objB = new ReferenceCountingGC (); // 對象之間相互循環引用,對象objA和objB之間的引用計數永遠不可能爲 0 objB.instance = objA; objA.instance = objB; objA = null; objB = null; System.gc(); }
上述代碼最後面兩句將objA和objB賦值爲null,也就是說objA和objB指向的對象已經不可能再被訪問,可是因爲它們互相引用對方,致使它們的引用計數器都不爲 0,那麼垃圾收集器就永遠不會回收它們。線程
經過一系列「GC roots」的對象做爲起始點,從這些節點開始向下搜索,搜索所走過的路徑成爲引用鏈(refenecre chain) ,當一個對象到GcRoot 沒有任何的引用鏈,則證實此對象不可用。code
Gcroot對象包括:對象
虛擬機棧(棧幀中的本地變量表) 中引用的對象。
方法區中類靜態屬性引用的對象
方法區中常量引用的對象
本地方法棧中JNI(native方法)引用的對象。blog
即時當一個對象不可達到,也並不是非死不可,這時它們處於一個緩行的階段要真正判處一個對象死亡,至少要經歷2次標記。第一次標記爲不可達到。當對象沒有覆蓋finalize() 方法,或者finalize方法已經被虛擬機調用了,虛擬機都被視爲不必執行(不必執行是否是直接回收?)隊列
若是一個對象被斷定有必要執行,則將這個對象放在一個F-Queue的隊列中,並由一個線程去執行它。finalize方法是對象逃脫死亡命運的最後機會。當在finalize方法中從新將之間賦值給了某個變量,那麼第二次標記就會被移除。若是對象第二次尚未逃脫,那麼基本就被回收了。
public class FinalizeEscapeGc { private static FinalizeEscapeGc instance = null; public void alive() { System.out.println("i'm alive"); } /** * 該方法只調用一次 * @throws Throwable */ @Override protected void finalize() throws Throwable { super.finalize(); System.out.println("finalize()"); FinalizeEscapeGc.instance = this; } public static void main(String[] args) throws InterruptedException { instance = new FinalizeEscapeGc(); instance = null; System.gc(); Thread.sleep(500);// finalize() method has a low priority to excute if (instance != null) { instance.alive(); } else { System.out.println("ooops,i'm dead"); } instance = null; System.gc(); Thread.sleep(500); if (instance != null) { instance.alive(); } else { System.out.println("ooops,i'm dead"); } } }
輸出:
finalize()
i’m alive
ooops,i’m dead
方法區在hotspot虛擬機稱爲永久代,永久代的垃圾收集主要回收兩部份內容:廢棄常量和無用的類。回收廢棄常量與回收堆相似,當一個字符串「abc」,進入了常量池,且沒有任何String對象叫「abc」,那麼它將會被回收。
判斷一個類爲無用的類:
該類的全部實例都被回收加載該類的classloader已經被回收該類對應java.lang.class對象沒有在任何地方引用,沒法經過反射訪問該類。