.net Finalize()期间的异常:您使用什么方法检测垃圾收集器时间异常?

.net Finalize()期间的异常:您使用什么方法检测垃圾收集器时间异常?,.net,garbage-collection,.net,Garbage Collection,我正在.NET中开发一个相当广泛的系统,它涉及许多系统编程。大多数情况下,我使用IDisposable模式来处理资源处置,但有时这不适用(或被错误地忽略),并且资源在Finalize()期间被销毁。这可能发生在COM互操作中,或者当析构函数调用Dispose()时,其中存在异常 基本上:当终结器可能抛出时,并不总是能够清楚地看到和处理每个场景。当它发生时,应用程序肯定会崩溃 我之所以特别关注这类问题,是因为创建或使用对象的线程不会调用终结器,因此几乎不可能将异常与创建对象的上下文联系起来。您得到

我正在.NET中开发一个相当广泛的系统,它涉及许多系统编程。大多数情况下,我使用IDisposable模式来处理资源处置,但有时这不适用(或被错误地忽略),并且资源在Finalize()期间被销毁。这可能发生在COM互操作中,或者当析构函数调用Dispose()时,其中存在异常

基本上:当终结器可能抛出时,并不总是能够清楚地看到和处理每个场景。当它发生时,应用程序肯定会崩溃

我之所以特别关注这类问题,是因为创建或使用对象的线程不会调用终结器,因此几乎不可能将异常与创建对象的上下文联系起来。您得到的只是一些通用的GC线程

那么,现在向公众提出一个问题:如果你解释了这些问题,你会如何控制它们?标记对象?使用第三方工具跟踪这些问题

另外:是否可能触发某种全局“终结器抛出”事件,至少记录发生了这个问题


EDIT1:非常感谢每一位提交了宝贵意见的人,我想我现在更清楚需要做什么了。我最不想从这次讨论中得到的是,如果有人知道在终结器中触发异常代码的方法(即使应用程序崩溃仍然不可避免),那么我至少可以记录它,而不必修改每个类的析构函数。

你的问题基于一个有点错误的前提,也就是说,不可能处理终结器可能抛出的每个场景。这正是您需要在这里实现的目标。在终结过程中发生的异常将终止进程。除非异常确实是致命的,在这种情况下让程序崩溃,否则您应该以不会使程序崩溃的方式处理此异常

有一个终结器抛出几乎和C++析构函数一样糟糕。对于主动(IDisposable.Dispose())和被动(终结器线程)Dispose操作,IDisposable的大多数实现都调用相同的方法。如果终结器版本正在抛出,那么活动的dispose很可能也会抛出。这就像一个C++析构函数抛出,将防止嵌套资源在某些情况下被正确地处理。p>


不要允许异常从终结器传播,除非它们对应用程序确实是致命的

apachedbcp在处理放弃的连接时,似乎会在打开连接时生成异常,以便存储堆栈跟踪,并在清理连接时将其吐出。对于未正确处置的资源,您可以尝试使用类似这样的技术来跟踪资源的初始化和使用方式,以便finalize方法可以生成有用的错误输出。

只有在.NET中直接拥有非托管资源的类才需要finalizer(即不仅通过IDisposable成员)。此类类必须使用MSDN中描述的标准模式实现IDisposable

终结器应该只处理非托管资源-通常的模式是调用“protectedvoiddispose(booldisposing)”方法,并将disposing参数设置为false

此方法通常采用以下方式实现:

protected void Dispose(bool disposing)
{
    if (disposing)
    {
        // Dispose managed resources here.
        // (e.g. members that implement IDisposable)
        // This could throw an exception, but will *not* be called from the finalizer
        ...

    }
    ... Dispose unmanaged resources here.
    ... no need for any exception handling.
    ... Unlikely to get an exception, and if you do it will be fatal.
}

由于您只处理非托管资源,因此通常不应引用任何托管对象,也不应包含任何异常处理。

我在类中执行以下操作,因此在调试版本中,我可以尝试捕获这些类型的内容

在调试版本中,执行断言以确保类被明确释放。执行另一个断言以确保终结器不会抛出。在发布/生产版本中,不会执行此检查以提高性能

C#代码
您所说的是完全正确的,但我的问题是:如果finalizer仍然抛出(由于bug或我无法控制的其他原因)-我能做什么?我看不到任何GC回调或事件允许我注册终结器的事实threw@galets,在这种情况下,您无法执行任何操作。终结器中的异常对进程来说是致命的,我知道无法从代码中重写此行为。如果您正在托管CL,可能会有一个异常R,但不是100%。
using System;
using System.Diagnostics;

namespace ConsoleApplication8
{
    class Program
    {
        class IReferenceUnmanagedMem : IDisposable
        {
#if(DEBUG)
            private static readonly string _ctorStackTrace = Environment.StackTrace;
#endif

            public IReferenceUnmanagedMem()
            {
            }

            ~IReferenceUnmanagedMem()
            {
#if(DEBUG)
                Debug.Fail("Dispose method not called.", _ctorStackTrace);
                try
                {
#endif
                    Dispose(true);
#if(DEBUG)
                }
                catch(Exception e)
                {
                    Debug.Fail("Dispose method threw exception in finalizer.", e.ToString());
                }
#endif
            }

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

            protected virtual void Dispose(bool inFinalizer)
            {
                if(inFinalizer)
                {
                    throw new Exception("I Know, this is a no-no.");
                }
            }
        }

        public static void Main()
        {
            IDisposable disposable = new IReferenceUnmanagedMem();
            disposable = null;
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }
    }
}