ImageSource/CreateBitmapSourceFromHBitmap的内存泄漏(使用AForge捕获网络摄像头时) [英] Memory Leak from ImageSource/CreateBitmapSourceFromHBitmap (while capturing webcam with 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).
这是我的 Bitmap
实例到答案通过 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:
- 此答案假定我正在从URI加载,而我可以将其加载到流中.
- 此答案似乎是假设我直接从我可以访问的流中加载位图数据,同样, 此博客文章建议创建一个流包装器.
-
Freeze
此博文不适用,因为根据我对Freeze
的呼叫是评论还是取消评论,泄漏不会改变. 此答案进一步证实了这一点. - 此答案,此答案,此答案和此博文.我已经在代码中这样做了.
- 来自此问题的信息建议我需要处理
Bitmap
的一部分,但是由于using
块,我已经在处理我自己创建的任何Bitmap
实例.
- 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 toFreeze
. 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 fromGetHbitmap
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 anyBitmap
instance that I create myself, thanks to theusing
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屋!