[英]Why is the finalize() method deprecated in Java 9?
(這個問題不同於你為什么要實現 finalize()?這個問題是關於 Java 平台的棄用,另一個問題是關於是否應該在應用程序中使用這種機制。)
為什么 Java 9 中不推薦使用finalize()
方法?
是的,它可能以錯誤的方式使用(比如從垃圾收集中保存一個對象 [盡管只有一次] 或嘗試關閉其中的一些本機資源 [盡管總比不關閉要好])以及許多其他方法可能會被錯誤地使用。
那么finalize()
真的如此危險或完全沒用,以至於有必要將其從 Java 中剔除嗎?
盡管問題是關於Object.finalize
方法的,但該主題實際上是關於作為一個整體的終結機制。 該機制不僅包括表面 API Object.finalize
,還包括有關對象生命周期的編程語言規范,以及對 JVM 中垃圾收集器實現的實際影響。
關於為什么從應用程序的角度來看難以使用終結,已經有很多文章。 請參閱問題為什么要實現 finalize()? Java 9 Cleaner 應該優先於最終確定嗎? 以及他們的回答。 另請參閱Effective Java,第 3 版,Joshua Bloch,第 8 項。
簡而言之,與使用終結器相關的問題的一些要點是:
眾所周知,它們很難正確編程
特別是,當對象意外(但正確)無法訪問時,它們可能會意外運行; 例如,請參閱我對這個問題的回答
終結很容易打破子類/超類關系
終結者之間沒有排序
JVM 最多調用一次給定對象的finalize
方法,即使該對象已“復活”
無法保證最終確定的及時性,甚至根本不會運行
沒有明確的注冊或注銷機制
以上是使用finalization的難點。 鑒於上述問題列表,任何正在考慮使用終結的人都應該重新考慮。 但是這些問題足以在 Java 平台中棄用終結嗎? 以下部分解釋了幾個其他原因。
最終確定可能使系統變得脆弱
即使您編寫了一個正確使用終結的對象,當您的對象集成到更大的系統中時,它也可能會導致問題。 即使您根本不使用終結,被集成到更大的系統中,其中某些部分使用終結,也會導致問題。 一般問題是創建垃圾的工作線程需要與垃圾收集器保持平衡。 如果垃圾收集器落后了,至少有一些收集器可以“停止世界”並做一個完整的收集來追趕。 最終確定使這種交互復雜化。 即使垃圾收集器與應用程序線程保持同步,終結也會引入瓶頸並減慢系統速度,或者可能導致釋放資源的延遲,從而導致這些資源耗盡。 這是系統問題。 即使使用終結的實際代碼是正確的,在正確編程的系統中仍然會出現問題。
最終確定會導致安全問題
適用於 Java的SEI CERT Oracle 編碼標准有一條規則MET12-J:不要使用終結器。 (注意,這是一個關於安全編碼的網站。)特別是,它說
終結器的不當使用可能導致垃圾收集就緒對象的復活,並導致拒絕服務漏洞。
Oracle 的Java SE 安全編碼指南更明確地說明了使用終結可能出現的潛在安全問題。 在這種情況下,使用終結的代碼不是問題。 相反,攻擊者可以使用終結來攻擊沒有正確保護自己的敏感代碼。 特別是,指南 7-3 / OBJECT-3部分規定,
可以通過終結器攻擊訪問非最終類的部分初始化實例。 攻擊者覆蓋子類中受保護的
finalize
方法並嘗試創建該子類的新實例。 這次嘗試失敗了……但攻擊者只是忽略任何異常並等待虛擬機對部分初始化的對象執行終結。 當這種情況發生時,惡意的finalize
方法實現被調用,使攻擊者可以訪問this
,this
是對正在被終結的對象的引用。 雖然對象只是部分初始化,但攻擊者仍然可以調用它的方法......
因此,平台中終結機制的存在給試圖編寫高保證代碼的程序員帶來了負擔。
最終確定增加了規范的復雜性
Java 平台由多個規范定義,包括語言規范、虛擬機規范和類庫 API。 最終確定的影響在所有這些方面的影響很小,但它反復地讓人感覺到它的存在。 例如,終結與對象創建有一個非常微妙的交互(這已經足夠復雜了)。 最終確定還出現了 Java 的公共 API,這意味着這些 API 的演變(到目前為止)需要與以前指定的行為保持兼容。 由於最終確定的存在,發展這些規范的成本更高。
完成增加了實現的復雜性
這主要是關於垃圾收集器。 垃圾回收的實現有好幾種,都需要付出實現終結的成本。 如果不使用終結,這些實現非常擅長最小化運行時開銷。 但是,實現仍然需要存在,並且需要正確且經過良好測試。 這是一個持續的開發和維護負擔。
概括
我們在別處看到,不建議程序員使用終結。 但是,如果某些東西沒有用,並不一定意味着它應該被棄用。 以上幾點說明了這樣一個事實,即即使不使用最終確定,平台中機制的存在也會增加持續的規范、開發和維護成本。 鑒於該機制缺乏實用性以及它帶來的成本,棄用它是有道理的。 最終,擺脫最終化將使每個人受益。
在撰寫本文時 (2019-06-04),還沒有從 Java 中刪除終結的具體計划。 然而,這樣做肯定是有意的。 我們已棄用Object.finalize
方法,但尚未將其標記為刪除。 這是正式建議程序員停止使用此機制。 非正式地知道不應該使用終結,但當然有必要采取正式的步驟。 此外,庫類中的某些finalize
方法(例如, ZipFile.finalize
)已被棄用“為了刪除”,這意味着這些類的終結行為可能會從未來版本中刪除。 最終,我們希望在 JVM 中禁用終結(可能首先是可選的,然后是默認情況下),並且在將來的某個時候實際上從垃圾收集器中刪除終結實現。
最終確定機制本質上存在問題。 最終確定可能導致性能問題,死鎖和掛起。 終結器中的錯誤可能導致資源泄漏;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.