要回答第一個問題,如果一個類實現IDisposable「正確」,那麼不應該有資源泄漏的危險。然而,在垃圾收集發生之前,非託管資源可能會延遲釋放。
考慮以下應用:
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
namespace LazyInit {
class DisposableClass : IDisposable {
private IntPtr _nativeResource = Marshal.AllocHGlobal(100);
private System.IO.MemoryStream _managedResource = new System.IO.MemoryStream();
public string ThreadName { get; set; }
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
~DisposableClass() {
Console.WriteLine("Disposing object created on thread " + this.ThreadName);
Dispose(false);
}
private void Dispose(bool disposing) {
if (disposing) {
// free managed resources
if (_managedResource != null) {
_managedResource.Dispose();
_managedResource = null;
}
}
// free native resources if there are any.
if (_nativeResource != IntPtr.Zero) {
Marshal.FreeHGlobal(_nativeResource);
_nativeResource = IntPtr.Zero;
}
}
}
static class Program {
private static Lazy<DisposableClass> _lazy;
[STAThread]
static void Main() {
List<Thread> t1 = new List<Thread>();
for (int u = 2, i = 0; i <= u; i++)
t1.Add(new Thread(new ThreadStart(InitializeLazyClass)) { Name = i.ToString() });
t1.ForEach(t => t.Start());
t1.ForEach(t => t.Join());
Console.WriteLine("The winning thread was " + _lazy.Value.ThreadName);
Console.WriteLine("Garbage collecting...");
GC.Collect();
Thread.Sleep(2000);
Console.WriteLine("Application exiting...");
}
static void InitializeLazyClass() {
_lazy = new Lazy<DisposableClass>(LazyThreadSafetyMode.PublicationOnly);
_lazy.Value.ThreadName = Thread.CurrentThread.Name;
}
}
}
使用LazyThreadSafetyMode.PublicationOnly
,它創建三個線程,每個實例Lazy<DisposableClass>
然後退出。
輸出看起來是這樣的:
獲勝的線程1
垃圾回收......
處置上線2
處置對象創建的對象上創建線程0
正在退出...
處置對象上線程1
創建正如在問題中提到,Lazy<>.LazyInitValue()
不檢查IDisposable的,並Dispose()
沒有被顯式調用,但仍所有三個對象最終被設置;兩個物體由於超出範圍而被丟棄並被垃圾收集,而第三個被丟棄在申請出口處。發生這種情況是因爲我們正在使用在所有託管對象被銷燬時調用的析構函數/終結器,並反過來使用它來確保釋放非託管資源。
對於第二個問題,人們猜測爲什麼沒有使用IDisposable檢查。也許他們沒有設想在實例化時分配非託管資源。
延伸閱讀:
更多關於如何正確實現IDisposable,看MSDN上here(這是我的例子中的一半是從來源)。
此外,還有是一個很好的SO文章here,這給了我見過的爲什麼的IDisposable應該以這種方式實現了最好的解釋。
這在.NET上被忽略了,這就是爲什麼我提供[LazyNeedle](https://github.com/theraot/Theraot/blob/master/Core/Theraot/Threading/Needles/LazyNeedle.cs)和[ LazyDisposableNeedle ](https://github.com/theraot/Theraot/blob/master/Core/Theraot/Threading/Needles/LazyDisposableNeedle.cs)。順便說一句,我[懶惰](https://github.com/theraot/Theraot/blob/master/Core/System/Lazy1.net35.cs)的模擬這種行爲,(看看右邊的碼)。 –
Theraot
2013-12-16 20:57:06