【发布时间】:2012-08-27 13:05:22
【问题描述】:
我有几个用于与 c++ dll 通信的非托管内存结构。
每个这样的结构都必须手动释放,所以我将它包装在实现 IDisposable 的 MyUnmanagedStructure 中。
我总是需要可变数量的这些结构,所以我有一个集合MyUnmanagedStructureCollection,它也实现了 IDisposable。
(参见下面的最小示例代码)
只要我的库的用户总是调用 Dispose() 或使用 using() {} 包装集合就没有问题,但我不能保证。即使用户不手动处理集合,我也不想泄漏内存。
当垃圾收集通过终结器调用MyUnmanagedStructureCollection.Dispose() 方法时,据我所知,我不能确定我的private List<MyUnmanagedStructure> 还没有被垃圾收集,那么我该如何处理每个结构那案子?
在我的最终代码中,我是否应该尝试遍历列表,希望它还没有被垃圾回收?
在 try/catch 块中执行此操作并捕获 ObjectDisposedException 是否是一种好习惯?
或者我应该让每个非托管结构“自生自灭”,依靠各个终结器,而在我的集合的终结器中什么都不做?
public class MyUnmanagedStructureCollection : IDisposable
{
private List<MyUnmanagedStructure> structures;
private bool disposed = false;
#region standard IDIsposable pattern
public ~MyUnmanagedStructureCollection()
{
this.Dispose(false);
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
// Dispose unmanaged resources
// Should not access managed resources,
// the garbage collection may have claimed them already!
// PROBLEM!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// this.structures is a List<MyUnmanagedStructure>; so is a managed resource!!!
foreach (var structure in this.structures)
structure.Dispose(disposing)
this.removeAllMemoryPressure();
if (disposing)
{
// Dispose managed resources.
this.structures.Clear();
this.structures = null;
}
}
disposed = true;
}
}
public class MyUnmanagedBuffer : IDisposable
{
...
}
【问题讨论】:
-
如果列表仍然从您的对象中引用,如何收集?只是集合中的对象可能已经完成(但尚未收集)。
-
好吧,我的对象和对象里面的List会被一起收集起来,据我了解,GC不保证会按照什么顺序销毁它们。不过我可能错了
-
GC不保证finalization的顺序。它保证尚未收集任何可从终结器访问的对象。
-
我的担忧源于我读到的关于 IDisposable 模式的常见建议,例如here。我读到的所有内容都声称我不应该从终结器访问托管对象。从我的终结器访问托管 List
真的省钱吗? -
集合的终结器只会增加不必要的开销。元素的终结者已经完成了工作。最终确定已经确定的元素的额外风险。只需删除集合终结器,它没有任何帮助。
标签: c# garbage-collection unmanaged idisposable finalizer