假設我有一個MyObject
對象,它有兩個接口:IMyContract
和IDisposable
。我有一個方法中的代碼:如果使用接口,則需要處置
IMyContract blah = new MyObject();
blah.Blah();
return;
這是一個潛在的內存泄漏,對嗎?它不需要是:
using (MyObject blah = new MyObject())
{
blah.Blah();
}
return;
假設我有一個MyObject
對象,它有兩個接口:IMyContract
和IDisposable
。我有一個方法中的代碼:如果使用接口,則需要處置
IMyContract blah = new MyObject();
blah.Blah();
return;
這是一個潛在的內存泄漏,對嗎?它不需要是:
using (MyObject blah = new MyObject())
{
blah.Blah();
}
return;
那麼,如果它實現IDisposable
你應該確實處置它。如果不這樣做 - 或者持續多久 - 沒有說什麼會泄漏,但是你應該有一個using
聲明來避免它。
(只是爲了澄清:內存是被泄露的至少容易的事情,因爲IDisposable
一般約爲非託管資源,如網絡連接等,這是可能的,當然 - 對象可能對分配一些內存句柄遠離GC的目光。任何實現IDisposable
持有直接引用非託管資源,也應該有一個終結,所以泄漏應該只是暫時的......但是這可能仍然是痛苦的。)
你可以請在您的第一個示例中進行處理:
IMyContract blah = new MyObject();
blah.Blah();
((IDisposable)blah).Dispose();
return;
不太清潔,但有時您必須使用接口。
另一種可能性是您的接口本身繼承IDisposable。然後,你可以使用:
using (IMyContract blah = new MyObject())
{
blah.Blah();
}
return;
請注意,如果'Blah'引發異常,您將無法進入第一種情況的'Dispose'行。 – 2010-09-16 18:49:44
如果IDisposable
是implemented properly(與調用Dispose()
並沒有SuppressFinalize
終結),垃圾收集器會得到它最終會。但是,using()
與try { ... } finally { object.Dispose(); }
相同,它將確定性地(明確地儘快)處置。如果您依賴垃圾收集器,您可能會驚訝需要處理多久。如果存在非託管資源,則可能會因爲它們尚未被釋放而迅速耗盡。
編輯:我第一次錯過了這一點。是的,當您使用MyObject
時,您應該Dispose()
與using()
正確。如果你有一個使用該接口,那麼你可以有類似其他代碼:
public IMyContract GetInterface()
{
using (MyObject obj = new MyObject())
{
obj.DoSomething();
return (IMyContract)obj;
}
}
的代碼,然後可以使用IMyContract contract = GetInterface();
,而不必擔心(或者甚至不知道),其餘的事情要處理。
我不知道你的意思,但你的答案意味着調用'object.Dispose'將決定性地釋放內存。事實並非如此。調用'Dispose'確定性地釋放該對象使用的任何非託管對象(當然,提供了'Dispose'方法正確實現),但它不影響垃圾收集堆。 – 2010-09-16 18:57:58
不,你說得對。 GC將調用終結器(如果它沒有被抑制),遵循標準的'IDisposable'模式會調用'Dispose(true)'來釋放非託管資源。 – 2010-09-16 19:05:24
從技術上講,你不能導致內存泄漏。但是,您最終可能會持有資源比必要的時間更長。
如果IMyContract
的實現者通常是一次性的(或可能是一次性的),那麼IMyContract
應繼承自IDisposable
。否則,你可以從IDisposable
繼承MyObject
。
無論哪種方式,該對象當然應該被處置。
不是默認的對象。Finalize()檢查實例以查看它是否爲IDisposable,並調用Dispose()方法? – KeithS 2010-09-16 19:07:22
@KeithS:「Object.Finalize默認不做任何事。」 http://msdn.microsoft.com/en-us/library/system.object.finalize(VS.71).aspx請注意,在C#中使用析構函數語法('〜ClassName()')來覆蓋Object。 Finalize()' – 2010-09-16 19:09:07