好程式設計師Java學習路線分享finalize()方法詳解

好程式設計師IT發表於2019-08-08

  好程式設計師 Java 學習路線分享 finalize() 方法詳解 ,前言,finalize() Object protected 方法,子類可以覆蓋該方法以實現資源清理工作, GC 在回收物件之前呼叫該方法。。

finalize 的作用

 (1)finalize() C++ 中的解構函式不是對應的。 C++ 中的解構函式呼叫的時機是確定的(物件離開作用域或 delete 掉),但 Java 中的 finalize 的呼叫具有不確定性

(2) 不建議用 finalize 方法完成“非記憶體資源”的清理工作,但建議用於:① 清理本地物件 ( 透過 JNI 建立的物件 ) ;② 作為確保某些非記憶體資源 ( Socket 、檔案等 ) 釋放的一個補充:在 finalize 方法中顯式呼叫其他資源釋放方法。其原因可見下文 [finalize 的問題

 finalize 的問題  

(1) 一些與 finalize 相關的方法,由於一些致命的缺陷,已經被廢棄了,如 System.runFinalizersOnExit() 方法、 Runtime.runFinalizersOnExit() 方法

(2)System.gc() System.runFinalization() 方法增加了 finalize 方法執行的機會,但不可盲目依賴它們

(3)Java 語言規範並不保證 finalize 方法會被及時地執行、而且根本不會保證它們會被執行

(4)finalize 方法可能會帶來效能問題。因為 JVM 通常在單獨的低優先順序執行緒中完成 finalize 的執行

(5) 物件再生問題: finalize 方法中,可將待回收物件賦值給 GC Roots 可達的物件引用,從而達到物件再生的目的

(6)finalize 方法至多由 GC 執行一次 ( 使用者當然可以手動呼叫物件的 finalize 方法,但並不影響 GC finalize 的行為 )

 

finalize 的執行過程 ( 生命週期 )

(1)  首先,大致描述一下 finalize 流程:當物件變成 (GC Roots) 不可達時, GC 會判斷該物件是否覆蓋了 finalize 方法,若未覆蓋,則直接將其回收。否則,若物件未執行過 finalize 方法,將其放入 F-Queue 佇列,由一低優先順序執行緒執行該佇列中物件的 finalize 方法。執行 finalize 方法完畢後, GC 會再次判斷該物件是否可達,若不可達,則進行回收,否則,物件“復活”。

(2)  具體的 finalize 流程:

   物件可由兩種狀態,涉及到兩類狀態空間,一是終結狀態空間  F = {unfinalized, finalizable, finalized} ;二是可達狀態空間  R = {reachable, finalizer-reachable, unreachable} 。各狀態含義如下:

 

unfinalized:  新建物件會先進入此狀態, GC 並未準備執行其 finalize 方法,因為該物件是可達的

finalizable:  表示 GC 可對該物件執行 finalize 方法, GC 已檢測到該物件不可達。正如前面所述, GC 透過 F-Queue 佇列和一專用執行緒完成 finalize 的執行

finalized:  表示 GC 已經對該物件執行過 finalize 方法

reachable:  表示 GC Roots 引用可達

finalizer-reachable(f-reachable) :表示不是 reachable ,但可透過某個 finalizable 物件可達

unreachable :物件不可透過上面兩種途徑可達


  (1) 新建物件首先處於 [reachable, unfinalized] 狀態 (A)

  (2) 隨著程式的執行,一些引用關係會消失,導致狀態變遷,從 reachable 狀態變遷到 f-reachable(B, C, D) unreachable(E, F) 狀態

  (3) JVM 檢測到處於 unfinalized 狀態的物件變成 f-reachable unreachable JVM 會將其標記為 finalizable 狀態 (G,H) 。若物件原處於 [unreachable, unfinalized] 狀態,則同時將其標記為 f-reachable(H)

  (4) 在某個時刻, JVM 取出某個 finalizable 物件,將其標記為 finalized 並在某個執行緒中執行其 finalize 方法。由於是在活動執行緒中引用了該物件,該物件將變遷到 (reachable, finalized) 狀態 (K J) 。該動作將影響某些其他物件從 f-reachable 狀態重新回到 reachable 狀態 (L, M, N)

  (5) 處於 finalizable 狀態的物件不能同時是 unreahable 的,由第 4 點可知,將物件 finalizable 物件標記為 finalized 時會由某個執行緒執行該物件的 finalize 方法,致使其變成 reachable 。這也是圖中只有八個狀態點的原因

  (6) 程式設計師手動呼叫 finalize 方法並不會影響到上述內部標記的變化,因此 JVM 只會至多呼叫 finalize 一次,即使該物件“復活”也是如此。程式設計師手動呼叫多少次不影響 JVM 的行為

  (7) JVM 檢測到 finalized 狀態的物件變成 unreachable ,回收其記憶體 (I)

  (8) 若物件並未覆蓋 finalize 方法, JVM 會進行最佳化,直接回收物件( O

  (9) 注: System.runFinalizersOnExit() 等方法可以使物件即使處於 reachable 狀態, JVM 仍對其執行 finalize 方法


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69913892/viewspace-2653048/,如需轉載,請註明出處,否則將追究法律責任。

相關文章