我有几个非托管内存结构用于与c ++ dll通信。
每个这样的结构都必须手动释放,因此我将其包装在实现MyUnmanagedStructure
的{{1}}中。
我总是需要可变数量的这些结构,所以我有一个集合IDisposable
,它也实现了IDisposable。
(请参阅下面的最小示例代码)
只要我的库的用户总是调用Dispose()或用MyUnmanagedStructureCollection
包装集合就没有问题,但我无法保证。即使用户没有手动处理集合,我也不想泄漏内存。
当垃圾收集通过终结器调用using() {}
方法时,据我所知,我不能确定我的MyUnmanagedStructureCollection.Dispose()
还没有被垃圾收集,所以如何处理在这种情况下每个结构?
在我的最终化代码中,我是否应该尝试迭代列表,希望它还没有被垃圾回收?
在try / catch块中执行此操作,捕获ObjectDisposedException是不错的做法?
或者我应该让每个unmanagedStructure“自生自灭”,依靠个人终结者,在我的收藏品的终结者中什么都不做?
private List<MyUnmanagedStructure>
答案 0 :(得分:2)
GC的工作方式是:
从正在运行终结器的对象引用的对象尚未被垃圾回收。
您唯一需要注意的是,最终确定的顺序是未定义的。因此,列表的元素可能尚未最终确定,但未收集。最终确保是单线程的,所以你也需要锁定。
人们通常会试图避免这种终结链,因为独立定型更简单。但是如果某些物体需要在其他物体之前处置,那么这种结构是不可避免的。
您还应该使用SafeHandle
来考虑关键定稿。
<强>可达性强>
最终确定的指导原则之一是Finalize方法不应该触及其他对象。人们有时会错误地认为这是因为已经收集了其他对象。然而,正如我所解释的那样,促进了可终结对象的整个可到达图形。
指南的真正原因是避免触及可能已经完成的对象。那是因为最终确定是无序的。
答案 1 :(得分:1)
由于您MyUnmanagedBuffer
类是MyUnmanagedStructureCollection
类的观点的托管资源,我认为它应该处理它。这意味着MyUnmanagedStructureCollection.Dispose(bool)
方法将如下所示。
protected virtual void Dispose(bool disposing) {
if (!disposed) {
// Dispose unmanaged resources
// Should not access managed resources,
// the garbage collection may have claimed them already!
if (disposing) {
// Dispose managed resources.
// This means that we try to dispose all items in the structures collection.
if (this.structures != null) {
foreach (var structure in this.structures) {
structure.Dispose(disposing);
this.removeAllMemoryPressure(); // What does this?
}
this.structures.Clear();
this.structures = null;
}
}
}
disposed = true;
}