当前位置:  开发笔记 > 编程语言 > 正文

如果程序意外关闭,IDisposable对象是否会被丢弃?

如何解决《如果程序意外关闭,IDisposable对象是否会被丢弃?》经验,为你挑选了4个好方法。

如果程序意外退出(异常或进程终止)会发生什么?是否存在此类(或其他)程序将终止的情况,但IDisposable对象将无法妥善处理?

我问的原因是因为我正在编写与外围设备通信的代码,我想确保它不会被置于糟糕的状态.



1> Patrick Hofm..:

如果原因是异常并从using块或try catch finally块中抛出,则将按原样处理.如果它没有被using块捕获,则它不会自动处理(就像应用程序正常关闭时不会那样).

一个样品:

IDisposable d1 = new X();

using (IDisposable d2 = new X())
{
    throw new NotImplementedException();
}

d1.Dispose();

d1没有处理,d2通常是.某些类型的异常可能会阻止using块的处理以及某些程序崩溃.如果原因是电源故障或系统崩溃,当然您无能为力.


有时会编写一个终结器(C#析构函数)来处理人们无法调用`Dispose`的情况,如上面的代码(使用`d1`).在调用`Dispose`的通常情况下,使用`GC.SuppressFinalize(this);`在该方法中,以避免(大部分)具有终结器的性能成本.当然,如果应用程序进程被操作系统主动杀死,这一切都无济于事(详情可能会有所不同).

2> Darin Dimitr..:

如果程序意外退出(例如,您终止进程),则绝对无法保证IDisposable.Dispose将调用该方法.你最好不要依赖它来做这类事件.必须通过代码手动调用Dispose方法,这不是CLR会自动为您调用的内容.


是的,如果它是FileStream,那么操作系统将保证在进程关闭时释放底层的非托管句柄.但这并不意味着将调用Dispose方法.只是操作系统知道如何在进程退出时回收文件句柄.

3> Yoh Deadfall..:

除了Patrick Hofman和Alexei的答案之外,即使应用程序正确终止,也可能无法执行清理.

您可能知道,Dispose当垃圾收集器收集实现IDisposable接口的对象时,不会调用该方法.但GC会调用该Finalize方法也称为终结器.在其中,您应该使用Dispose Pattern编写清理逻辑.是的,.Net Framework将尝试运行所有终结器,但没有保证它们会被执行.

例如,下面的程序有很长的终结器.因此,.Net将终止该过程,您将永远不会看到该消息.

class FinalizableObject
{
    ~FinalizableObject()
    {
        Thread.Sleep(50000);
        Console.WriteLine("Finalized");
    }
}

class Program
{
    static void Main(string[] args)
    {
        new FinalizableObject();
    }
}

这可能是由任何长时间运行的操作引起的,例如释放网络句柄或其他需要很多时间的操作.

因此,您不应该依赖终结器和一次性物体.但是所有打开的内核对象句柄都会自动关闭,所以你不必担心它们.

除了答案之外,我建议你阅读一些关于终结器和GC的有趣文章:

    每个人都以错误的方式思考垃圾收集(Raymond Chen)

    当你知道的一切都是错的时候,第一部分(Eric Lippert)

    当你知道的一切都是错的时候,第二部分(Eric Lippert)

    终止进程(MSDN)



4> Alexei..:

使用控制台应用程序进行的一个非常简单的测试表明,在进程终止时不调用Dispose:

class DisposableTest : IDisposable
{
    public void Dispose()
    {
        Console.WriteLine("Dispose called");
    }
}

...

using (DisposableTest sw = new DisposableTest())
{
    Thread.Sleep(20000);
}

使用任务管理器终止进程不会触发Disposable.Dispose()方法.等待20秒钟.

因此,如前所述,当应用程序崩溃或被杀死时,不要依赖于一次性对象.但是,异常应该触发它.我只是想知道是否异常,例如StackOverflowExceptionOutOfMemoryException将始终触发Dispose().

[编辑]

刚刚测试了我的好奇心:

StackOverflowException 获取进程终止,因此不调用Dispose()

OutOfMemoryException 允许正常调用Dispose()

推荐阅读
雨天是最美
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有