简体   繁体   English

在图片框控件中显示位图后处置位图

[英]Dispose Bitmap after showing it in a picturebox control

I would like to know why the garbage collector cannot keep track of the amount of memory used by the unmanaged part of a bitmap and release this resource when needed.我想知道为什么垃圾收集器无法跟踪位图的非托管部分使用的内存量并在需要时释放此资源。

I discovered it when a loop in a background thread called the following function causing an exception after a while:当后台线程中的循环调用以下函数导致一段时间后出现异常时,我发现了它:

    private delegate void setImageCallback();
    private void showFrame()
    {
        if (pboxCam.InvokeRequired)
        {
            this.Invoke(new setImageCallback(showFrame));
        }
        else
        {
            Bitmap bmp = new Bitmap(getBitmapFromCam());
            Graphics g = Graphics.FromImage(bmp);
            g.DrawRectangle(RectanglePen, 10, 10, 50, 30);
            g.Dispose();
            pboxCam.Image = bmp;
        }
    }

Then I tried to release bmp at the end of the function, but the picturebox doesn't show up the image anymore.然后我尝试在函数结束时释放 bmp,但图片框不再显示图像。 The solution below does work, but there is something I don't like.下面的解决方案确实有效,但有些我不喜欢。 What do you think?你怎么认为?

    Bitmap bmp;

    private delegate void setImageCallback();
    private void showFrame()
    {
        if (pboxCam.InvokeRequired)
        {
            this.Invoke(new setImageCallback(showFrame));
        }
        else
        {
            if (bmp!=null) bmp.Dispose();
            bmp = new Bitmap(getBitmapFromCam());
            Graphics g = Graphics.FromImage(bmp);
            g.DrawRectangle(RectanglePen, 10, 10, 50, 30);
            g.Dispose();
            pboxCam.Image = bmp;
        }
    }

You're doing it right.你做得对。 The GC is tracking the Bitmap object, and it will release it eventually. GC 正在跟踪Bitmap对象,它最终会释放它。 The key word being "eventually".关键词是“最终”。

To reclaim the managed bmp instance, it first has to run into memory pressure.要回收托管bmp实例,它首先必须遇到内存压力。 That occurs at about 1 MiB for gen-0 collections or so.对于 0 代左右的集合,这种情况发生在大约 1 MiB 处。 I'm not sure about the precise number, but the key element is that it's a lot.我不确定确切的数字,但关键是它很多。 You're going to have thousands of bitmaps, if not more, before you even get to gen-0 collection - and you usually need a gen-2 to execute finalizers (though take that with a grain of salt, I have no idea where I found that information).甚至在进行 gen-0 集合之前,您将拥有数千个位图,如果不是更多的话-并且您通常需要一个 gen-2 来执行终结器(尽管对此持保留态度,我不知道在哪里我找到了那个信息)。

Even when the GC does eventually run (in practice, you'll run out of memory long before that), it will start executing the finalizers on a separate thread.即使当 GC 最终运行时(实际上,您会在此之前很久就耗尽内存),它也会开始在单独的线程上执行终结器。 It has no idea about the unmanaged resources, so it has to rely on the finalizer code, which it runs serially.它不知道非托管资源,因此它必须依赖于串行运行的终结器代码。 It has no idea how much unmanaged memory is allocated at all, and cannot figure that in its memory checks.它根本不知道分配了多少非托管内存,也无法在其内存检查中计算出来。

So, the key thing is to always run Dispose on IDisposable objects.因此,关键是始终在IDisposable对象上运行Dispose The GC might not even get the chance to start the finalizers before you run out of memory, because it's only induced by managed memory pressure.在内存耗尽之前,GC 甚至可能没有机会启动终结器,因为它只是由托管内存压力引起的。 It has no idea about the unmanaged memory (if any).它不知道非托管内存(如果有的话)。 That's not the GCs fault, it really can't tell - after all, in your precise case, the memory is shared.这不是 GC 的错误,它真的无法判断 - 毕竟,在您的确切情况下,内存是共享的。 The GC can't know if it even should release that memory - that's up to the Bitmap.Finalize to decide. GC 甚至不知道它是否应该释放该内存 - 这取决于Bitmap.Finalize来决定。

That's also the reason why you really want to make everything that uses any IDisposable or unmanaged memory, also IDisposable - to make sure the caller can release the native resource as soon as possible.这也是为什么你真的想让所有使用任何IDisposable或非托管内存的东西,也是IDisposable - 以确保调用者可以尽快释放本机资源。

This doesn't apply just to unmanaged memory - waiting for the GC to dispose of eg.这不仅适用于非托管内存- 等待 GC 处理例如。 a file handle or a socket connection is a bad idea, since you really don't want to hold those longer than necessary.文件句柄或套接字连接是一个坏主意,因为您真的不想将它们保存的时间超过必要的时间。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM