如果我没有调用dispose()会发生什么?

12
    public void screenShot(string path)
    {
        var bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width,
                                        Screen.PrimaryScreen.Bounds.Height,
                                        PixelFormat.Format32bppArgb);

        var gfxScreenshot = Graphics.FromImage(bmpScreenshot);
        gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X,
                                    Screen.PrimaryScreen.Bounds.Y,
                                    0,
                                    0,
                                    Screen.PrimaryScreen.Bounds.Size,
                                    CopyPixelOperation.SourceCopy);

        bmpScreenshot.Save(path, ImageFormat.Png);
    }

我曾使用这段代码来截取我的电脑屏幕。

但今天我发现了一个叫做Bitmap.Dispose()的方法。

当调用Dispose()时和不调用有什么区别?对代码运行是否至关重要?


2
http://www.devx.com/dotnet/Article/33167 - Kamil Budziewski
阅读有关“垃圾收集器”的内容 - Arash
1
许多.NET程序员在其代码中从未使用过Dispose()方法。而唯一一个.NET类很少能够顺利运行的是Bitmap类。这些类倾向于占用大量未经处理的内存以存储像素数据,因此当您创建过多的截图时,就会出现崩溃情况。 - Hans Passant
4个回答

20

如果一个类型实现了IDisposable接口,你一定要调用Dispose方法(无论是显式调用还是通过using块调用)。

如果我不调用dispose()会发生什么?

如果你不这样做,析构函数(finalizer)将负责释放资源;然而,它有一些缺点:

  • 非确定性:finalizer由GC在专用线程上执行。 GC决定何时运行它们。 如果在程序的主窗口中保留了对对象的引用,则可能直到退出应用程序才会执行finalizer。
  • 开销:除非禁止了finalizer,否则GC必须完成一些对象的销毁工作。
  • 危险:如果finalizer抛出异常,它被认为是致命的并将导致整个应用程序崩溃。

2

必须调用Dispose。如果不这样做,就会有未受管控的资源,例如GDI对象,它们将无法进行清理。这意味着将导致内存泄漏。

因此,确保调用Dispose(或更好地使用using (...) { ... })。


调用 'Dispose()' 或使用 'using (...) { ... }' 是一样的吗? - user2101976
3
@ArthurPark 是的,它们是严格等价的。请参见 https://dev59.com/BWgu5IYBdhLWcg3w6bOo。尽管如此,`using` 更好,因为它已经实现了 try/finally 模式,所以即使有异常抛出,它也可以确保对象被正确处理。 - ken2k

2
“Dispose”方法来自“IDisposable”接口,执行以下操作:
执行与释放、释放或重置非托管资源相关联的应用程序定义任务。
基本上可以说使用的资源不会立即释放。即使它们不再需要。 但只有在垃圾收集器释放它们时才会释放。
有关更多信息,请查看MSDN: IDisposable Interface 此主题的其他有用链接:

0

基本上你的代码应该长成这样

public void screenShot(string path)
{
    using (var bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width,
                                    Screen.PrimaryScreen.Bounds.Height,
                                    PixelFormat.Format32bppArgb))

    {
        var gfxScreenshot = Graphics.FromImage(bmpScreenshot);
        gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X,
                                Screen.PrimaryScreen.Bounds.Y,
                                0,
                                0,
                                Screen.PrimaryScreen.Bounds.Size,
                                CopyPixelOperation.SourceCopy);

        bmpScreenshot.Save(path, ImageFormat.Png);
    }
}

这可以确保位图对象使用的非托管资源得到适当释放。如果没有正确处理,单个位图不会真正遇到麻烦,但一旦开始批量处理,情况就变得关键了。不正确地处理将导致内存不足问题,我曾经看到过由于编码不当而导致内存迅速填满。


抱歉我们同时发布了答案。这是正确的答案,我会删除我的。 - Stephen Brickner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接