ImageSource/CreateBitmapSourceFromHBitmap的内存泄漏(使用AForge捕获网络摄像头时) [英] Memory Leak from ImageSource/CreateBitmapSourceFromHBitmap (while capturing webcam with AForge)

查看:123
本文介绍了ImageSource/CreateBitmapSourceFromHBitmap的内存泄漏(使用AForge捕获网络摄像头时)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将网络摄像头捕获的所有内容输出到 AForge.NET 库.

I am trying to output whatever is captured from a webcam to an Image control in a WPF window. I am using the AForge.NET library.

不幸的是,在成功捕获了几分钟之后,我得到了

Unfortunately, after a few minutes of successful capturing, I am getting an OutOfMemoryException. Likewise, as soon as I start capturing, I can see my memory usage rise continuously in the task manager until the moment of the exception (although there have been a few occasions where memory usage kept rising, then steeply dropped back to its original state, and then kept rising again to the point of the exception).

这是我的 ImageSource 主要基于答案通过 Sascha Hennig ):

This is my code for the handler of the NewFrame event of the VideoCaptureDevice class (whose code for converting the Bitmap instance to an ImageSource is largely based on an answer by Sascha Hennig):

[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);

private void videoSource_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
    try
    {
        using (var streamBitmap = (Bitmap)eventArgs.Frame.Clone()) {
            BitmapSource bitmapSourceVideo;

            var hBitmap = streamBitmap.GetHbitmap();
            try
            {
                bitmapSourceVideo = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                    hBitmap,
                    IntPtr.Zero,
                    Int32Rect.Empty,
                    BitmapSizeOptions.FromEmptyOptions());
            }
            finally
            {
                DeleteObject(hBitmap);
            }
            bitmapSourceVideo.Freeze();

            Dispatcher.BeginInvoke(new ThreadStart(delegate
                                                       {
                                                           videoControl.Source = bitmapSourceVideo;
                                                       }));
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.ToString());
    }
}

如果您想知道,似乎需要调用eventArgs.Frame.Clone().可以在此处找到说明,也可以在

In case you wonder, the call to eventArgs.Frame.Clone() seems to be required. Explanations can be found here, and possibly here.

在试图找出问题的根源时,我注释掉了这段代码的各个部分,直到达到这种状态为止:

While trying to isolate the source of the issue, I have commented out various portions of this code until I arrived at this state:

[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);

private void videoSource_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
    try
    {
        using (var streamBitmap = (Bitmap)eventArgs.Frame.Clone()) {
            BitmapSource bitmapSourceVideo;

            var hBitmap = streamBitmap.GetHbitmap();
            try
            {/*
                bitmapSourceVideo = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                    hBitmap,
                    IntPtr.Zero,
                    Int32Rect.Empty,
                    BitmapSizeOptions.FromEmptyOptions());
            */}
            finally
            {
                DeleteObject(hBitmap);
            }
            /*
            bitmapSourceVideo.Freeze();

            Dispatcher.BeginInvoke(new ThreadStart(delegate
                                                       {
                                                           videoControl.Source = bitmapSourceVideo;
                                                       }));*/
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.ToString());
    }
}

(显然,这不会在窗口上绘制任何东西,但是现在这还不重要.)此版本的方法不具有内存泄漏的功能.通过调用

(Obviously, this doesn't draw anything to the window, but that is beside the point now.) This version of the method does not feature the memory leak. Removing the comment signs around the statement with the call to CreateBitmapSourceFromHBitmap brings the memory leak back. What am I missing here?

关于看似相似的问题,有很多资源,没有一个可以帮助我找到解决方案:

There have been various resources about seemingly similar problems, none of which have helped me find a solution:

  • This answer assumes I am loading from a URI that I could instead load into a stream.
  • This answer seems to assume I am loading the bitmap data directly from a stream that I can access, and likewise, this blogpost suggests to create a stream wrapper.
  • The Freeze solution from this blogpost should not apply, as the leak does not change based on whether I comment or uncomment my call to Freeze. This is further corroborated by this answer.
  • This answer, this answer, this answer, and all answers to this question point out that DeleteObject needs to be invoked once the handle obtained from GetHbitmap is no longer needed. This is also suggested by this blogpost. I am already doing that in the code.
  • Information from this question suggests I need to dispose of the Bitmap, but I am already disposing of any Bitmap instance that I create myself, thanks to the using block.
  • This forum thread sounds vaguely similar, but it ends in an inconclusive way.

推荐答案

我的直觉告诉我,这与bitmapSourceVideo位于委托中有关,因此创建了一个闭包而不被清除.

My instinct tells me that it is something to do with the bitmapSourceVideo being inside the delegate, and therefore creating a closure and not being cleaned up.

编辑

尝试

        Dispatcher.BeginInvoke(new ThreadStart(delegate
        {
            videoControl.Source = bitmapSourceVideo;
            bitmapSourceVideo = null;
        }));

这篇关于ImageSource/CreateBitmapSourceFromHBitmap的内存泄漏(使用AForge捕获网络摄像头时)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆