safehandle 和析构函数
safehandle?是一種析構機制,她和析構函數有什么分別。
?
首先要理解析構函數。析構函數在.net中是沒有順序的,因此你不能假定另一個對象的析構函數在你之后運行,哪怕它是你的成員!如果你的成員也有析構函數,那么你能做什么,什么不應該做?
第一,在析構函數運行時,你不應該假設它沒清理資源,而去試圖清理它。合理的做法是它應該自己實現dispose模式,你在dispose(true)段落可以調用它的dispose()函數.因為dispose是可多次重入的,因此不會有問題。如果它沒有,那就別去理他,因為它的析構函數會釋放它的非托管資源。這樣的好處是,我可以分別控制每一個實現dispose模式的對象成員的控制時機,而dispose(false)也就是析構函數,能夠作為防御性代碼,幫你把忘記的“非托管”資源清理掉。
第二,一個實現了dispose的.net對象,外部應該怎樣看它?不應該把它所控制的資源看作非托管資源,既然他實現了dispose,也就是“有自行管理”的,因此只需要在dispose(true)段落調用它的dispose函數,讓其在顯式清理實際時產生效果便可。這是我對dispose模式的理解。dispose模式分兩類資源,一類是托管,一類是非托管。托管和非托管并不是純粹站在.net角度出發,而是應該理解為“自己管理”和“其他對象管理”的差別。你的對象自己打開文件,就自己負責關閉,而其他對象,包括成員對象,他們控制的資源就由他們控制,在當前立場上看,都是“受托管的”。
第三,你的對象的 dispose 應該被顯式調用(也就是最外層對象)!這個是dispose模式的關鍵,因為析構函數只是負責自身非托管資源的釋放,它沒有參與整套資源管理流程。如果你不顯式調用(或者另外編寫代碼),清理流程是不可能正確執行的。
第四。為何析構函數不負責dispose的所有內容,首先是析構順序的不確定性,而資源管控流程需要順序;其次,析構函數沒有明確的調用時機,而dispose可以在任意時刻調用。
?
然后是safehandle,safehandle據說有經過優化,但是它也不會搶先在析構函數階段運行,在我測試中是這種情況。因此,我不知道優化在那里了。只是添加了一種模式,比析構函數更舵控制,畢竟是外部獨立的類,而且系統已經針對多種資源提供了恰當的子類,可惜沒有針對com對象資源。
?
總的來說,最佳實踐是:
1.如果safehandle子類有的系統資源,如句柄,非托管內存等等,用safehandle?模式。
2.如果子成員正確實現了dispose,把它視為托管資源,在dispose(true)中調用。
3.如果子成員沒有實現dispose,但是控制了相關資源,也就是你要負責子對象相關資源的顯式控制,千萬別用析構函數清理,因為析構函數階段,子成員可能已經把它關聯的資源給釋放掉了(未必以正確的方式,只是對資源失去控制力),你無法再清理。因為GC對任意對象的析構函數調用順序是不確定的。(這一狀況只能要求你在編程階段正確調用dispose,而絕不能遺忘調用,否則就有資源泄漏。com for .net就是如此設計的)
4.一般情況,dispose(true)負責對象鏈的清理流程,dispose(false)即析構函數,負責自身非托管資源。如果沒有這部分可以不寫析構函數。
5.dispose的實現方式要規范。最終dispose要顯式調用!
?
規范的dispose該注意哪些,這里補充一下:
private bool disposedValue = false; // 要檢測冗余調用protected virtual void Dispose(bool disposing){if (!disposedValue){if (disposing){// TODO: 釋放托管狀態(托管對象)。//這里應該包含成員對象的dispose//大部分被包裝的資源的處理過程都寫在這里,比如退出過程:先保存,然后關閉,等等//safehandle.Dispose();}// TODO: 釋放未托管的資源(未托管的對象)并在以下內容中替代終結器。// TODO: 將大型字段設置為 null。//這里是自身管理的一些資源的釋放,比如通過c api調用的一些非托管資源app = null;disposedValue = true;}}//TODO: 僅當以上 Dispose(bool disposing) 擁有用于釋放未托管資源的代碼時才替代終結器。~Excel(){// 請勿更改此代碼。將清理代碼放入以上 Dispose(bool disposing) 中。Dispose(false);}// 添加此代碼以正確實現可處置模式。void IDisposable.Dispose(){// 請勿更改此代碼。將清理代碼放入以上 Dispose(bool disposing) 中。Dispose(true);// TODO: 如果在以上內容中替代了終結器,則取消注釋以下行。//也就是有析構函數就有下面這行代碼,表示顯式運行dispose時,GC不需要再運行析構函數,提高性能GC.SuppressFinalize(this);}?
轉載于:https://www.cnblogs.com/Nobel/p/5190395.html
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的safehandle 和析构函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: YTU 2586: 填空题B-字画鉴别
- 下一篇: 将CAGradientLayer当做ma