【发布时间】:2015-05-11 05:42:23
【问题描述】:
我正在尝试将从网络摄像头捕获的任何内容输出到 WPF 窗口中的Image control。我正在使用AForge.NET 库。
不幸的是,在成功捕获几分钟后,我收到了OutOfMemoryException。同样,当我开始捕获时,我可以在任务管理器中看到我的内存使用量不断上升,直到出现异常的那一刻(尽管有几次内存使用量一直在上升,然后又急剧下降到原来的状态,然后不断上升到异常点)。
这是VideoCaptureDevice class 的NewFrame event 处理程序的代码(其将Bitmap 实例转换为ImageSource 的代码主要基于an answer 的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()。可以在here 和here 找到解释。
在试图找出问题的根源时,我已经注释掉了这段代码的各个部分,直到我到达这个状态:
[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 删除语句周围的注释符号会导致内存泄漏恢复。 我在这里错过了什么?
有很多关于看似相似问题的资源,但没有一个能帮助我找到解决方案:
- This answer 假设我是从一个 URI 加载的,而我可以将其加载到流中。
- This answer 似乎假设我直接从我可以访问的流中加载位图数据,同样,this blogpost 建议创建一个流包装器。
- 来自this blogpost 的
Freeze解决方案不应该适用,因为泄漏不会根据我是否评论或取消评论我对Freeze的调用而改变。 this answer 进一步证实了这一点。 -
This answer、this answer、this answer 和all answers to this question 指出,一旦不再需要从
GetHbitmap获得的句柄,就需要调用DeleteObject。 this blogpost 也建议这样做。我已经在代码中这样做了。 - 来自this question 的信息表明我需要处置
Bitmap,但由于using块,我已经处置了我自己创建的任何Bitmap实例。 - This forum thread 听起来有点相似,但它以一种不确定的方式结束。
【问题讨论】:
-
你有想过这个吗?
-
@Tronald:不,恐怕我从来没有跟进过这个项目(现在已经记不起它的内容了)。
-
是的,那是不久前的事了,所以认为这是一个长镜头。不过感谢您的回复!
标签: .net wpf memory-leaks aforge imagesource