如果调用者忘记使用Dispose(),如何释放不会被垃圾回收的托管资源?

时间:2009-07-26 08:26:01

标签: .net

在我的代码中,我有一个创建新线程的类。这个新线程有一个Dispatcher,因此除非我调用

,否则线程不会完成
Dispatcher.CurrentDispatcher.InvokeShutdown();

线程不能在我的课外引用。 所以我在想:当我的对象被垃圾收集时,如何确保我的线程完成?

一个响应是使用IDisposable,但是如果有人忘记调用Dispose(),那么该线程将永远不会停止,因此它不是解决方案。

另一个响应是两个使用Dispose + Destructor,但我听说我们应该只使用析构函数来释放非托管资源。我走到了尽头。

什么是最佳解决方案?

3 个答案:

答案 0 :(得分:2)

一种选择是仅对调试版本使用终结器。不要让它“很好地”关闭线程:让它非常突出地记录警告。这应该可以帮助您隔离您忘记妥善处理对象的地方。

然而,它并非万无一失,而且它具有使调试和发布代码不同的不良特性。

您的调度员通常会经常接收事件吗?如果长时间没有收到任何事件,你能否至少记录一下警告?

一个相当讨厌的选择是让调度员对一次性对象有一个弱引用。它可以定期检查对象是否已被垃圾收集(使用WeakReference.IsAlive)并自行关闭(如果是这样)。同样,这不是非常令人愉快(并且应该记录警告)。

答案 1 :(得分:1)

“Dispose + Destructor”解决方案对我来说似乎很好。正如乔恩所说,你可以采用一些技巧来检测是否错过了一次Dispose呼叫,但是在终结器呼叫中停止线程将是一个额外的保护措施。

顺便说一句,线程是一种非托管资源。

答案 2 :(得分:1)

关于处置和最终确定here有很多有用的信息。显然,如果您正在编写可重用的类或库以供其他程序员使用,您不能假设将始终调用Dispose方法,因此实现终结器是明智的:

public void Dispose()  {
    Dispose(true);
    GC.SuppressFinalize(this); 
}

protected virtual void Dispose(bool disposing) {
    if (disposing) {
        // Free other state (managed objects).
    }
    // Free your own state (unmanaged objects).
    // Set large fields to null.
}

~MyClass() {
    Dispose (false);
}

似乎 在这种情况下,您有以下选择:

  • 如果未调用Dispose
  • ,则会在终结器中清理资源
  • 与上述相同,但也会记录警告或错误
  • 如果调用终结器,则会大声失败

你可以通过保护它们来防止最后2个被编译到发行版中:

~MyClass() {
    Dispose (false);
    #if DEBUG
        // log a warning or scream at the developer in some way
    #endif
}