3 回答

TA貢獻1842條經驗 獲得超22個贊
將處理與垃圾收集分開是很重要的。它們是完全不同的東西,有一個共同點我將在一分鐘內到達。
Dispose
,垃圾收集和定稿
當你編寫一個using
語句時,它只是try / finally塊的語法糖,因此Dispose
即使using
語句正文中的代碼拋出異常,也會調用它。這并不意味著該對象在塊的末尾被垃圾收集。
處置是關于非托管資源(非內存資源)。這些可能是UI句柄,網絡連接,文件句柄等。這些是有限的資源,因此您通常希望盡快釋放它們。IDisposable
只要您的類型“擁有”非托管資源,您應該直接(通常通過一個IntPtr
)或間接(例如通過a Stream
,a SqlConnection
等)實現。
垃圾收集本身只是關于內存 - 只有一點點扭曲。垃圾收集器能夠找到無法再引用的對象,并釋放它們。它不會一直尋找垃圾 - 只有當它檢測到它需要時(例如,如果堆的一個“代”耗盡內存)。
扭曲是最終確定。垃圾收集器保存一個不再可訪問的對象列表,但它們有一個終結器(用~Foo()
C#編寫,有點令人困惑 - 它們與C ++析構函數完全不同)。它在這些對象上運行終結器,以防它們需要在釋放內存之前進行額外的清理。
在該類型的用戶忘記以有序方式處理它的情況下,終結器幾乎總是用于清理資源。因此,如果您打開FileStream
但忘記調用Dispose
或Close
,終結器最終將為您釋放基礎文件句柄。在一個寫得很好的程序中,終結者幾乎不應該在我看來。
將變量設置為 null
設置變量的一個小問題null
- 為了垃圾收集,這幾乎不需要。如果它是一個成員變量,你有時可能想要這樣做,盡管根據我的經驗,不再需要一個對象的“部分”。當它是一個局部變量時,JIT通常足夠聰明(在發(fā)布模式下),以便知道何時不再使用引用。例如:
StringBuilder sb = new StringBuilder();
sb.Append("Foo");
string x = sb.ToString();
// The string and StringBuilder are already eligible
// for garbage collection here!
int y = 10;
DoSomething(y);
// These aren't helping at all!
x = null;
sb = null;
// Assume that x and sb aren't used here
一個時間它可能是值得設置一個局部變量null
是當你在一個循環(huán),循環(huán)的一些分支機構需要使用變量,但你知道你已經達到在你做的不是一個點。例如:
SomeObject foo = new SomeObject();for (int i=0; i < 100000; i++){ if (i == 5) { foo.DoSomething(); // We're not going to need it again, but the JIT // wouldn't spot that foo = null; } else { // Some other code }}
實現IDisposable / finalizers
那么,你自己的類型應該實現終結器嗎?幾乎肯定不是。如果你只間接持有非托管資源(例如你有FileStream
一個成員變量),那么添加你自己的終結器將無濟于事:當你的對象出現時,流幾乎肯定有資格進行垃圾收集,所以你可以依賴FileStream
有一個終結者(如果有必要 - 它可能會引用別的東西,等等)。如果你想“近乎”直接持有一個非托管資源,那么SafeHandle
你的朋友 - 它需要一些時間才能開始,但這意味著你幾乎 不需要再次編寫終結器。如果你對資源有一個非常直接的處理(a IntPtr
),你通常只需要一個終結器,你應該轉向SafeHandle
你盡快做。(有兩個鏈接 - 理想情況下讀取兩個。)
Joe Duffy 有一套很長的關于終結者和IDisposable的指導方針(與很多聰明的人合寫)值得一讀。值得注意的是,如果你密封你的類,它會讓生活變得更容易:當你的類被設計為繼承時,覆蓋Dispose
調用新的虛Dispose(bool)
方法等的模式才有意義。
這有點絮絮叨叨,但請你澄清一下你想要的地方:)

TA貢獻1828條經驗 獲得超4個贊
這兩項行動彼此沒有太大關系。當您將引用設置為null時,它只是這樣做。它本身并不會影響所引用的類。您的變量不再指向它以前使用的對象,但對象本身不變。
當你調用Dispose()時,它是對象本身的方法調用。無論Dispose方法做什么,現在都在對象上完成。但這不會影響您對該對象的引用。
唯一的重疊區(qū)域是,當不再有對象的引用時,它最終會被垃圾收集。如果類實現了IDisposable接口,那么在對象被垃圾收集之前將調用Dispose()。
但是,在將引用設置為null之后,這不會立即發(fā)生,原因有兩個。首先,可能存在其他引用,因此它根本不會收集垃圾,其次,即使這是最后一個引用,所以現在它已經準備好被垃圾收集,在垃圾收集器決定刪除之前不會發(fā)生任何事情物體。
在對象上調用Dispose()不會以任何方式“殺死”對象。它通常用來清理,使該對象可以被安全地刪除之后,但最終,沒有什么神奇的有關Dispose,它只是一個類的方法。
- 3 回答
- 0 關注
- 923 瀏覽
添加回答
舉報