C#實(shí)現(xiàn)IDisposable接口釋放非托管資源
Reference
Why using finalizers is a bad idea
當(dāng)在一個(gè)類中使用了另外一個(gè)實(shí)現(xiàn)了IDisposable
的類作為一個(gè)成員屬性時(shí), 此時(shí)這個(gè)類就有必要也去實(shí)現(xiàn)IDisposable接口, 以確保在合適的實(shí)際釋放非托管資源, 到底該如何正確的實(shí)現(xiàn)這個(gè)接口呢? 當(dāng)然這只是需要實(shí)現(xiàn)IDisposable接口其中一種情況
完整示例
示例的Foo
類中包含了一個(gè)Stream
類型的_stream
成員, 因此需要為Foo類實(shí)現(xiàn)IDisposable模式
public class Foo : IDisposable { private bool _disposed; private readonly Stream? _stream; public Foo() { _stream = File.Create("1.txt", 2048); } ~Foo() { CleanupUnmanagedResources(); } private void CleanupUnmanagedResources() { if (_disposed) return; // 釋放非托管資源 _stream?.Dispose(); _disposed = true; } public void Dispose() { CleanupUnmanagedResources(); GC.SuppressFinalize(this); } }
為什么要實(shí)現(xiàn)Foo析構(gòu)函數(shù)
因?yàn)槿诵缘娜觞c(diǎn)(??)
哈哈, 其實(shí)因?yàn)槲覀冊(cè)谑褂?code>Foo時(shí)可能會(huì)忘記手動(dòng)調(diào)用其Dispose
方法, 這個(gè)時(shí)候如果沒有析構(gòu)函數(shù)的話, 很可能導(dǎo)致資源永遠(yuǎn)得不到釋放最終釀成內(nèi)存泄漏的慘劇.
當(dāng)然啦, 在析構(gòu)函數(shù)中釋放非托管資源可能會(huì)給GC
帶來額外的開銷, 所以最好的做法是依然是使用using
塊保證能夠及時(shí)的調(diào)用Dispose方法, 這里使用析構(gòu)函數(shù)只是為了防止意外的發(fā)生. 至于為什么說在析構(gòu)函數(shù)中釋放非托管資源會(huì)導(dǎo)致額外的GC
開銷呢, 這涉及到GC回收過程,GC在處理包含析構(gòu)函數(shù)的類時(shí)不會(huì)立即將此類回收, 而是會(huì)被GC標(biāo)記為下一代, 這樣這個(gè)被標(biāo)記為下一代的類只有在GC決定回收下一代的垃圾對(duì)象時(shí), 才會(huì)被真正回收掉, 這樣一來就會(huì)導(dǎo)致額外的內(nèi)存和性能開銷了.
Dispose方法中為什么要調(diào)用GC.SuppressFinalize
GC.SuppressFinalize
方法可以告訴GC
不需要在調(diào)用此類的析構(gòu)函數(shù)(Finalizers)了;
因?yàn)樵?code>Foo類的析構(gòu)函數(shù)中調(diào)用了Foo.CleanupUnmanagedResources方法, 當(dāng)GC
回收此類調(diào)用此類析構(gòu)函數(shù)時(shí), 有可能會(huì)導(dǎo)致兩次調(diào)用Foo.CleanupUnmanagedResources(第一次是Dispose
方法中調(diào)用的)導(dǎo)致額外的開銷,
所以當(dāng)我們手動(dòng)調(diào)用了Foo.Dispose(通過是通過using
語(yǔ)法糖)后, 就需要告訴GC
, "你回收我的時(shí)候用不著調(diào)用我的析構(gòu)函數(shù)了, 該釋放的資源我早就釋放掉了已經(jīng)", 轉(zhuǎn)換成代碼就是GC.SuppressFinalize
以上就是C#實(shí)現(xiàn)IDisposable接口釋放非托管資源的詳細(xì)內(nèi)容,更多關(guān)于C# IDisposable接口釋放資源的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C#導(dǎo)入導(dǎo)出EXCEL文件的代碼實(shí)例
這篇文章主要介紹了C#導(dǎo)入導(dǎo)出EXCEL文件代碼實(shí)例,代碼的流程和方法都很詳細(xì),需要的朋友可以參考下2014-04-04C#中IList<T>與List<T>的區(qū)別深入解析
本篇文章主要是對(duì)C#中IList<T>與List<T>的區(qū)別進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過來參考下,希望對(duì)大家有所幫助2014-01-01C#預(yù)處理指令之#line,#pragma warning 詳細(xì)解析
#line 指令可能由生成過程中的自動(dòng)中間步驟使用。例如,如果行從原始的源代碼文件中移除,但是您仍希望編譯器基于文件中的原始行號(hào)生成輸出,則可以移除行,然后用 #line 模擬原始行號(hào)2014-01-01C#生成指定范圍內(nèi)的不重復(fù)隨機(jī)數(shù)
對(duì)于隨機(jī)數(shù),大家都知道,計(jì)算機(jī)不 可能產(chǎn)生完全隨機(jī)的數(shù)字,所謂的隨機(jī)數(shù)發(fā)生器都是通過一定的算法對(duì)事先選定的隨機(jī)種子做復(fù)雜的運(yùn)算,用產(chǎn)生的結(jié)果來近似的模擬完全隨機(jī)數(shù),這種隨機(jī)數(shù)被稱 作偽隨機(jī)數(shù)。偽隨機(jī)數(shù)是以相同的概率從一組有限的數(shù)字中選取的。2015-05-05