Image.RotateFlip 泄漏内存:/

发布于 2024-11-19 01:04:15 字数 1909 浏览 3 评论 0原文

虽然我已经编程了大约 11 年(主要是 VB6,最近 6 个月是 C#),但这是第一次真正提出问题:) 我已经从 interwebz 找到了所有答案,但这个问题我无法自己解决。您的网站是我获得最佳答案的最有帮助的地方之一!

我将展示我正在使用的代码(相关内容的摘录)。问题是,当使用 RotateFlip 方法时,内存会迅速增加到约 200M,然后在一段时间后被 GC 收集。调用它的主要方法每秒迭代大约 30 次,因此性能在这里至关重要。我尝试过使用图形矩阵变换,但这有时会失败并显示非翻转图像。该应用程序本身基于使用网络摄像头、隐藏预览、拍摄回调图片并将其显示在图片框中。然后它在另一个类的 if 上覆盖一个矩形。这就是使用回调而不是预览窗口的原因。

Capture.cs 类:

internal Bitmap LiveImage;

    int ISampleGrabberCB.BufferCB(double bufferSize, IntPtr pBuffer, int bufferLen)
    {
        LiveImage = new Bitmap(_width, _height, _stride, PixelFormat.Format24bppRgb, pBuffer);

        if (ExpImg) // local bool, used rarely when the picture saving is triggered
        {
            LiveImage.RotateFlip(RotateFlipType.RotateNoneFlipY);
            var a = LiveImage.Clone(new Rectangle(Currect.Left, Currect.Top, Currect.Width, Currect.Height),
                                    LiveImage.PixelFormat);
            using (a)
                a.Save("ocr.bmp", ImageFormat.Bmp);

        }
        else // dmnit, rotateflip leaks like h*ll but matrix transform doesn't sometimes flip :S
        {
            LiveImage.RotateFlip(RotateFlipType.RotateNoneFlipY);
            /*using (var g = Graphics.FromImage(LiveImage))
            {
                g.Transform = _mtx;
                g.DrawImage(LiveImage, 0, 0);
            }*/
        }
        GC.Collect(); // gotta use it with rotateflip, otherwise it gets crazy big, like ~200M :O
        return 0;
    }
}

在主窗体中,我有一个正在更新图片框中的图片的事件:

private void SetPic()
{
    pctCamera.Image = _cam.LiveImage;
    _cam.PicIsFree = false;
}

因为我需要将图像获取到位于另一个类中的主窗体,所以我认为最合乎逻辑的是暴露的位图,它在每个回调帧。 我不想使用矩阵变换的原因是因为它速度较慢,有时以这种速度无法翻转图像,并且这种行为的频率对于具有不同硬件功能和 CPU 速度的不同 PC 有很大不同,也是最快的帧速率1.2GHz CPU 的 30fps 经常显示这一点。

那么,你能帮我弄清楚吗?我实际上并没有在当前版本中使用它,我正在使用注释掉的矩阵变换,因为我对使用 GC.Collect 感觉不好:(

谢谢!!!

Although I have been programming for about 11 years(mostly VB6, last 6 months C#), it's THE first time to actually ask a question :) I have found all my answers from teh interwebz but this issue i can't solve myself. Your site is among the most helpful places i have got the best answers from!

I will show the code i'm using (an extract of what's relevant). Problem is that when using RotateFlip method then the memory is increasing rapidly to ~200M and then get's collected by GC after some time. The main method calling it iterates about 30 times per second so the performance is of utmost importance here. I have tried using graphics matrix transform but this sometimes fails and shows non-flipped image. The application itself is based on using a webcam, hiding the preview, taking the callback picture and showing it in picturebox. It then overlays a rectangle on if from another class. That's the reason to use callback and not preview window.

Capture.cs class:

internal Bitmap LiveImage;

    int ISampleGrabberCB.BufferCB(double bufferSize, IntPtr pBuffer, int bufferLen)
    {
        LiveImage = new Bitmap(_width, _height, _stride, PixelFormat.Format24bppRgb, pBuffer);

        if (ExpImg) // local bool, used rarely when the picture saving is triggered
        {
            LiveImage.RotateFlip(RotateFlipType.RotateNoneFlipY);
            var a = LiveImage.Clone(new Rectangle(Currect.Left, Currect.Top, Currect.Width, Currect.Height),
                                    LiveImage.PixelFormat);
            using (a)
                a.Save("ocr.bmp", ImageFormat.Bmp);

        }
        else // dmnit, rotateflip leaks like h*ll but matrix transform doesn't sometimes flip :S
        {
            LiveImage.RotateFlip(RotateFlipType.RotateNoneFlipY);
            /*using (var g = Graphics.FromImage(LiveImage))
            {
                g.Transform = _mtx;
                g.DrawImage(LiveImage, 0, 0);
            }*/
        }
        GC.Collect(); // gotta use it with rotateflip, otherwise it gets crazy big, like ~200M :O
        return 0;
    }
}

In main form i have an event that's updating the picture in the picturebox:

private void SetPic()
{
    pctCamera.Image = _cam.LiveImage;
    _cam.PicIsFree = false;
}

Because i need to get the image to main form which is in another class then i figured the most logical is the exposed Bitmap which is updated on every callback frame.
The reason i don't want to use matrix transform is because it's slower and sometimes with this speed it fails to flip the image and the frequency of such behavior is quite different with different PC's with different hardware capabilities and CPU speeds, also the fastest framerate 30fps with a 1.2GHz CPU shows this very frequently.

So, can you help me to figure it out? I'm not actually using it in current version, i'm using the commented-out matrix transform because i feel bad for using GC.Collect :(

Thank You!!!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

听,心雨的声音 2024-11-26 01:04:15
pctCamera.Image = _cam.LiveImage;

像您观察到的那样,大量内存使用表明您错过了在某处调用 Dispose() 的机会,让位图使用的非托管资源(主要是内存)提前释放,而不是让垃圾收集器来释放。引用的声明就是一种这样的情况,您没有处理图片框引用的旧图像。使固定:

if (pctCamera.Image != null) pctCamera.Image.Dispose();
pctCamera.Image = _cam.LiveImage;
pctCamera.Image = _cam.LiveImage;

Heavy memory usage like you observe is a sure sign that you missed an opportunity to call Dispose() somewhere, letting the unmanaged resources (memory mostly) used by a bitmap get released early instead of letting the garbage collector do it. The quoted statement is one such case, you are not disposing the old image referenced by the picture box. Fix:

if (pctCamera.Image != null) pctCamera.Image.Dispose();
pctCamera.Image = _cam.LiveImage;
拥醉 2024-11-26 01:04:15

您可以像这样重写代码:

internal Bitmap LiveImage;

int ISampleGrabberCB.BufferCB(double bufferSize, IntPtr pBuffer, int bufferLen)
{
    using (LiveImage = new Bitmap(_width, _height, _stride, PixelFormat.Format24bppRgb, pBuffer))
    {
        LiveImage.RotateFlip(RotateFlipType.RotateNoneFlipY);
        if (ExpImg) // local bool, used rarely when the picture saving is triggered
        {
            var a = LiveImage.Clone(new Rectangle(Currect.Left, Currect.Top, Currect.Width, Currect.Height),
                                    LiveImage.PixelFormat);
            using (a)
                a.Save("ocr.bmp", ImageFormat.Bmp);
        }
    }

    return 0;
}

位图 是一个 图像 类,并实现IDispose。当您每次创建Bitmap时,我建议使用using语句来自动释放资源。

You can rewrite your code like this:

internal Bitmap LiveImage;

int ISampleGrabberCB.BufferCB(double bufferSize, IntPtr pBuffer, int bufferLen)
{
    using (LiveImage = new Bitmap(_width, _height, _stride, PixelFormat.Format24bppRgb, pBuffer))
    {
        LiveImage.RotateFlip(RotateFlipType.RotateNoneFlipY);
        if (ExpImg) // local bool, used rarely when the picture saving is triggered
        {
            var a = LiveImage.Clone(new Rectangle(Currect.Left, Currect.Top, Currect.Width, Currect.Height),
                                    LiveImage.PixelFormat);
            using (a)
                a.Save("ocr.bmp", ImageFormat.Bmp);
        }
    }

    return 0;
}

Bitmap is an Image class, and implements the IDispose. As you create Bitmap each time, I suggest to use using statement for automatically freeing the resources.

居里长安 2024-11-26 01:04:15

GC.Collect 正是针对这种情况而设计的。收集数据是释放数据的唯一方法,在创建巨大的位图时,这是唯一的方法。 GC.Collect 真的会减慢速度吗?

除此之外,您应该保持位图副本的数量尽可能少。

GC.Collect is there for this situation. Collecting the data is the ONLY way to free it and when creating HUGE bitmaps its the way to go. Does a GC.Collect really slow things down?

Other then that you should keep the number of bitmap copies as low as possible.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文