【问题标题】:Memory Leak from ImageSource/CreateBitmapSourceFromHBitmap (while capturing webcam with AForge)ImageSource/CreateBitmapSourceFromHBitmap 的内存泄漏(使用 AForge 捕获网络摄像头时)
【发布时间】:2015-05-11 05:42:23
【问题描述】:

我正在尝试将从网络摄像头捕获的任何内容输出到 WPF 窗口中的Image control。我正在使用AForge.NET 库。

不幸的是,在成功捕获几分钟后,我收到了OutOfMemoryException。同样,当我开始捕获时,我可以在任务管理器中看到我的内存使用量不断上升,直到出现异常的那一刻(尽管有几次内存使用量一直在上升,然后又急剧下降到原来的状态,然后不断上升到异常点)。

这是VideoCaptureDevice classNewFrame event 处理程序的代码(其将Bitmap 实例转换为ImageSource 的代码主要基于an answerSascha 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()。可以在herehere 找到解释。

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

[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());
    }
}

(很明显,这不会在窗口上绘制任何东西,但现在这已经无关紧要了。)这个版本的方法没有内存泄漏。通过调用CreateBitmapSourceFromHBitmap 删除语句周围的注释符号会导致内存泄漏恢复。 我在这里错过了什么?

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

【问题讨论】:

  • 你有想过这个吗?
  • @Tronald:不,恐怕我从来没有跟进过这个项目(现在已经记不起它的内容了)。
  • 是的,那是不久前的事了,所以认为这是一个长镜头。不过感谢您的回复!

标签: .net wpf memory-leaks aforge imagesource


【解决方案1】:

我的直觉告诉我,这与 bitmapSourceVideo 在委托中有关,因此创建了一个闭包并且没有被清理。

编辑

试试

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

【讨论】:

  • 我已经调查过了,但我究竟应该如何清理BitmapSource?不是disposable 什么的。 This answer(尽管它不被接受......)意味着不需要进一步清理。
  • 如果您将整个方法包装在 Dispatcher.BeginInvoke 中,而不仅仅是设置源代码,会发生什么情况?
  • 我可以尝试,但我不希望从中产生任何好处 - 特别是,如果我可以依靠 eventArgs.Frame 在事件处理程序之后仍然存在,我会感到惊讶在调用它的线程中终止。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-05
  • 1970-01-01
  • 2010-11-23
相关资源
最近更新 更多