【问题标题】:C# Picturebox memory leakC# 图片框内存泄漏
【发布时间】:2013-03-22 04:28:15
【问题描述】:

我浏览了几页类似的查询,实施了大部分建议,但目前似乎找不到任何可行的方法。希望我没有忽略一些显而易见的事情。

好的,所以我正在使用 AForge.net 来捕获图像。它提供了一个事件,每个接收到的新帧都会触发该事件,在我的代码中如下所示:

private void videoSourcePlayer_NewFrame(object sender, ref Bitmap image)
    {
        framesRecieved++;
        try
        {
            if (!stopCapturing)
            {
                if (pictureBox1.Image != null)
                {
                    pictureBox1.Image.Dispose();
                }
                pictureBox1.Image = image.Clone(new Rectangle(0, 0, image.Width, image.Height), image.PixelFormat);
            }

        }
        catch { }
        finally { GC.Collect(); }
    }

只要窗口保持静止,内存使用就非常稳定,但只要我抓住窗口窗体并开始移动它,内存使用就会不断上升。我被引导相信它可能与图片框有关的原因是,一旦我将“stopCapturing”布尔值设置为 true,即使我在屏幕上移动窗口,内存也会停止上升。 “stopCapturing”不用于其他任何事情,事件继续正常触发,唯一的区别是图片框中显示的图像。我不知道原因,所以任何帮助将不胜感激。

PS:不确定是否相关,但我的工作站有 2 个屏幕。

【问题讨论】:

  • 首先移除空的 catch 和 GC.Collect。
  • 不确定Clone 的需要。我以前用过new Bitmap(image) 没有问题。

标签: c# .net aforge


【解决方案1】:

Bitmap.Clone() 进行浅拷贝,实际字节仍归调用者所有,因此这可能会导致各种麻烦。 你需要做一个深拷贝。

例如AForge way:

Bitmap bmp = AForge.Imaging.Image.Clone(image);

或者 GDI+ 方式(也可以使用 lockbits 等以获得更好的性能):

Bitmap bmp = new Bitmap(image.Width, image.Height, image.PixelFormat);
Graphics g = Graphics.FromImage(bmp);
g.DrawImageUnscaled(image, Point.Empty);

【讨论】:

    【解决方案2】:

    我想知道你为什么要克隆图像。让我感到震惊的是,您应该只在 pictureBox1.Image 为空或图像的尺寸或像素格式发生变化时分配新图像:

    private bool BitmapChanged(Bitmap old, Bitmap new)
    {
        return old == null || old.PixelFormat != new.PixelFormat ||
            old.Width != new.Width || old.Height != new.Height;
    }
    
    private Bitmap MakeSimilarBitmap(Bitmap source)
    {
        Bitmap copy = new Bitmap(source.Width, source.Height, source.PixelFormat);
        return copy;
    }
    
    private void DrawOnto(Image im, Bitmap source)
    {
        using (Graphics g = Graphics.FromImage(im)) {
            g.DrawImage(source, 0, 0);
        }
    }
    

    那么当你得到一个框架时,你会做这样的事情:

    Image im = BitmapChanged(pictureBox1.Image as Bitmap, srcBmp) ?
                              MakeSimilarBitmap(image) : pictureBox1.Image;
    DrawOnto(im, srcBmp);
    bool same = im == pictureBox1.Image;
    if (same)
        pictureBox1.Invalidate();
    else {
        Image old = pictureBox1.Image;
        pictureBox1.Image = im;
        old.Dispose();
    }
    

    【讨论】:

    • 您需要进行复制,因为该图像归 VideoSource 所有。它将自行决定处置。另见:aforgenet.com/framework/docs/html/…
    • 我的意思是您将内容复制到一个保留的位图中,而不是每帧分配一个新副本。
    猜你喜欢
    • 2012-08-17
    • 2018-09-19
    • 2022-01-10
    • 2020-02-15
    • 1970-01-01
    • 2013-10-01
    • 1970-01-01
    • 2016-01-27
    相关资源
    最近更新 更多