要回答第一个问题,如果一个类实现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