.net Finalize()期间的异常:您使用什么方法检测垃圾收集器时间异常?
我正在.NET中开发一个相当广泛的系统,它涉及许多系统编程。大多数情况下,我使用IDisposable模式来处理资源处置,但有时这不适用(或被错误地忽略),并且资源在Finalize()期间被销毁。这可能发生在COM互操作中,或者当析构函数调用Dispose()时,其中存在异常 基本上:当终结器可能抛出时,并不总是能够清楚地看到和处理每个场景。当它发生时,应用程序肯定会崩溃 我之所以特别关注这类问题,是因为创建或使用对象的线程不会调用终结器,因此几乎不可能将异常与创建对象的上下文联系起来。您得到的只是一些通用的GC线程 那么,现在向公众提出一个问题:如果你解释了这些问题,你会如何控制它们?标记对象?使用第三方工具跟踪这些问题 另外:是否可能触发某种全局“终结器抛出”事件,至少记录发生了这个问题.net Finalize()期间的异常:您使用什么方法检测垃圾收集器时间异常?,.net,garbage-collection,.net,Garbage Collection,我正在.NET中开发一个相当广泛的系统,它涉及许多系统编程。大多数情况下,我使用IDisposable模式来处理资源处置,但有时这不适用(或被错误地忽略),并且资源在Finalize()期间被销毁。这可能发生在COM互操作中,或者当析构函数调用Dispose()时,其中存在异常 基本上:当终结器可能抛出时,并不总是能够清楚地看到和处理每个场景。当它发生时,应用程序肯定会崩溃 我之所以特别关注这类问题,是因为创建或使用对象的线程不会调用终结器,因此几乎不可能将异常与创建对象的上下文联系起来。您得到
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();
}
}
}