最后确定()期间例外:您使用什么方法来检测垃圾收集时异常?(Exceptions during Fi

2019-07-21 12:25发布

我正在开发的.NET相当广泛的系统,它涉及到很多系统编程的。 大多数时间,我使用了IDisposable模式来处理资源的处置,但有时这是不适用(或错误地离开了)和资源被最终确定期间被毁()。 这可能会在COM时,析构函数调用Dispose()发生互操作,或者和有它内部的一个例外。

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

为什么我关心的是具体这类问题的原因是,终结器不是由创建或使用对象的线程调用,所以它几乎是不可能完成的任务异常配合在其中创建对象的上下文。 所有你得到一些通用的GC线程。

所以,现在的问题给公众 :如果你考虑这些类型的问题,你会怎么做来控制它们? 标签的对象? 使用第三方工具,它允许跟踪那些问题?

另外:是否有可能引发某种全球性的“终结扔”事件,至少记录,这非常的问题发生了什么?

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

Answer 1:

终结时,才需要.NET中的直接拥有的非托管资源(即不仅通过了IDisposable成员)班。 使用标准模式作为MSDN描述的这种类必须实现IDisposable。

终结应该永远只能处置非托管资源-通常的模式是调用一个方法“保护无效的Dispose(BOOL处置)”设置为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.
}

既然你永远只能处置非托管资源,你一般不应该引用任何管理的对象,不应该需要包括任何异常处理。



Answer 2:

你的问题是基于一个错误的有些前提,那就是它无法处理的每个场景,其中一个终结可能会抛出。 这正是你需要在这里实现什么。 终止过程中出现的异常将终止进程。 除非例外是真正致命的,在这种情况下让程序崩溃,你应该处理此异常,不会崩溃的程序的方式。

有一个终结罚球几乎是具有C ++的析构函数抛出的那样糟糕。 IDisposable接口调用的大多数实现转化为主动(IDisposable.Dispose())和被动(终结器线程)同样的方法处理操作。 如果终结版本扔那么它可能或可能是积极的处置可以奉送。 此,很象C ++的析构函数投掷,将防止在某些情况下正确地布置的嵌套资源。

不允许,除非他们是真正致命的,你的应用程序异常,从一个终结传播。



Answer 3:

我做我的班以下,所以在调试版本,我可以尝试捕获这些类型的东西。

在调试版本,一个断言做是为了保证类是显式地布置。 另一个断言做是为了确保终结不会抛出。 在发行/制作版本,此检查不执行到更高的性能。

C#代码

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();
        }
    }
}


Answer 4:

Apache的DBCP,用废弃的连接问题时,似乎当打开一个连接,以便存储堆栈跟踪吐出来时,它清除连接生成异常。 对于那些没有被正确配置资源,你可以尝试使用这样的技术来追踪资源如何初始化和使用,使finalize方法能够产生有用的错误输出。



文章来源: Exceptions during Finalize(): what methodology are you using to detect garbage collector-time exceptions?