如何判斷物件已死
參考計數演算法(Reference Counting)
在物件中添加一個參考計數器,每當一個地方參考它,計數器就加一;當參考失效時,計數器就減一;任何時刻計數器為零的物件就是不可能在被使用的,
客觀的說,參考計數演算法雖然占用了一些額外的記憶體空間來計數,原理簡單,效率也很高,但是在Java領域,至少主流的Java虛擬機里面都沒有選用參考計數法來進行記憶體管理,主要原因是,這個演算法有很多例外要處理,比如物件之間相互回圈參考解決起來就很麻煩,
import org.junit.Test;
public class ReferenceCountIngGC {
public Object instance = null;
private static final int _1MB = 1024*1024;
private byte[] bigSize = new byte[2*_1MB];
public static void teseGC(){
ReferenceCountIngGC A = new ReferenceCountIngGC();
ReferenceCountIngGC B = new ReferenceCountIngGC();
A.instance = B;
B.instance = A;
A = null;
B = null;
//假設在這行發生GC,A和B是否能被回收
System.gc();
}
public static void main(String[] args) {
teseGC();
}
}

由上述GC日志可知,里面包含了“880K->645K(249344K)”表示“GC前java堆已使用容量”–>“GC后java堆的已使用容量(java堆總容量”,這意味著Java虛擬機并沒有因為這兩個物件互相應用就放棄回收它們,這也說明了Java虛擬機并不是通過參考計數演算法來判斷物件是否存活的,
可達性分析演算法(Reachability Analysis)
**基本思路:**通過一系列稱為“GC Root”的根物件作為起始節點集,從這些節點開始根據參考關系向下搜索,搜索程序所走過的路徑稱為“參考鏈”,如果某個物件到GC Roots間沒有任何參考鏈相連,或者圖論的話來說就是從GC Roots到這個物件不可達時,則證明這個物件是不可能再被使用的,演算法具體程序如下圖所示

在Java技術體系里面,固定可以作為GC Roots的物件包括以下幾種
- 在虛擬機堆疊(堆疊中 的本地變數表)中參考的物件,例如各個執行緒被呼叫的方法堆疊中使用到的引數、區域變數、臨時變數等,
- 在方法區中類靜態屬性參考的物件,例如Java類的參考型別靜態變數,
- 在方法區中常量參考的物件,例如字串常量池(String Table)里的參考,
- 在本地方法堆疊中JNI(本地方法)參考的物件,
- Java虛擬機內部的參考,如基本資料型別對應的Class物件,一些常駐的例外物件(NullPointException、OutOfMemoryError)等,以及系統類加載器,
- 所有被同步鎖(synchronized)持有的物件,
- 反映Java虛擬機內部情況的JMXBean、JVMTI中注冊的回呼、本地代碼快取等,
參考
在JDK1.2版之后,java對參考的概念進行了擴充,將參考分為了強參考(Strongly Reference)、軟參考(Soft Reference)、弱參考(Weak Reference)和虛參考(Phantom Reference,參考強度逐次減弱,
- 強參考是最傳統的“參考”的定義,是指在程式代碼之中普遍存在的參考賦值,即類似“ Object obj = new ObjectQ”這種參考關系,無論任何情況下,只要強參考關系還存在,垃圾收集器就永遠不會回收掉被參考的物件,
- 軟參考是用來描述一些還有用,但非必須的物件,只被軟參考關聯著的象,在系統將要發生記憶體溢位例外前,會把這些物件列進回收范圍之中進行第二次回收,如果這次回識訓沒有足夠的記憶體,才會拋出記憶體溢位例外,在 JDK 1.2 版之后提供了SofReference 類來實作軟參考,
- 弱參考也是用來描述那些非必須物件,但是它的強度比軟參考更弱一些,被弱參考關聯的物件只能生存到下一次垃圾收集發生為止,當垃圾收集器開始作業,無論當前記憶體是否足夠,都會回收掉只被弱參考關聯的物件,在 JDK 1.2 版之后提供了WeakReference 類來實作弱參考,
- 虛參考也稱為“幽靈參考”或者“幻影參考”,它是最弱的一種參考關系,一個物件是否有虛參考的存在,完全不會對其生存時間構成影響,也無法通過虛參考來取得一個物件實體,為一個物件設定虛參考關聯的唯一目的只是為了能在這個物件被收集器回收時收到一個系統通知,在 JDK 1.2 版之后提供了 PhantomReference 類來實作虛參考,
生存還是死亡?
即使在可達性分析演算法中判定為不可達物件,也不是“非死不可”的,這時候他們暫時還處于“緩刑”階段,要真正宣告一個物件死亡,至少要經歷兩次標記程序:如果對即使在可達性分析演算法中判定為不可達的物件,也不是“非死不可”的,這時候它們象在進行可達性分析后發現沒有與 GC Roots 相連接的參考鏈,那它將會被第一次標記,隨后進行一次篩選,篩選的條件是此物件是否有必要執行 finalize()方法,假如物件沒有覆寫finalize()方法,或者 finalize()方法已經被虛擬機呼叫過,那么虛擬機將這兩種情況都視為“沒有必要執行”,
如果這個物件被判定為確有必要執行 finalize()方法,那么該物件將會被放置在一個名為 F-Queue 的佇列之中,并在稍后由一條由虛擬機自動建立的、低調度優先級的 Finalizer執行緒去執行它們的 finalize()方法,這里所說的“執行”是指虛擬機會觸發這個方法開始運行,但并不承諾一定會等待它運行結束,這樣做的原因是,如果某個物件的 finalize0)方法執行緩慢,或者更極端地發生了死回圈,將很可能導致 F-Queue 佇列中的其他物件永久
處于等待,甚至導致整個記憶體回收子系統的崩潰,finalize()方法是物件逃脫死亡命運的最后一次機會,稍后收集器將對 F-Queue 中的物件進行第二次小規模的標記,如果物件要在finalize()中成功拯救自己——只要重新與參考鏈上的任何一個物件建立關聯即可,
方法區的回收
方法區的垃圾收集主要回收兩部分內容:1.廢棄的常量,2.不在使用的型別
不在被使用的類條件:
- 該類所有的實體都已經無法被回收,也就是Java堆中不存在該類以及任何派生子類的實體
- 加載該類的類加載器已經被回收,
- 該類對應的Java.lang.class物件沒有在任何地方被參考,無法在任何地方通過反射訪問該類的方法
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/273707.html
標籤:java
下一篇:字符流、列印流、轉換流、檔案流
