使用大图像时,垃圾收集器太慢

时间:2016-02-12 15:26:43

标签: c# memory-management memory-leaks garbage-collection dispose

我正在使用Emgu OpenCV从网络摄像头抓取图像,并希望使用WPF Image控制来显示它们。
所以我需要将图像从Mat转换为与Image控件兼容的内容。所以我从Emgu的例子中选择了这个类:

public static class BitmapSourceConvert
{
    /// <summary>
    /// Delete a GDI object
    /// </summary>
    /// <param name="o">The poniter to the GDI object to be deleted</param>
    /// <returns></returns>
    [DllImport("gdi32")]
    private static extern int DeleteObject(IntPtr o);

    /// <summary>
    /// Convert an IImage to a WPF BitmapSource. The result can be used in the Set Property of Image.Source
    /// </summary>
    /// <param name="image">The Emgu CV Image</param>
    /// <returns>The equivalent BitmapSource</returns>
    public static BitmapSource ToBitmapSource(IImage image)
    {
        using (System.Drawing.Bitmap source = image.Bitmap)
        {
            IntPtr ptr = source.GetHbitmap(); //obtain the Hbitmap
            BitmapSource bs = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                ptr,
                IntPtr.Zero,
                Int32Rect.Empty,
                System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());

            DeleteObject(ptr); //release the HBitmap
            return bs;
        }
    }
}

这就像小图像的魅力(例如640 x 480)。使用任务管理器(我在Windows 8上)时,我看到使用的内存增加和减少。工作正常。

但是当使用像1920x1080这样的大图像时,应用程序会在短时间内崩溃,但不会有更多内存。再次查看任务管理器时,我可以看到内存消耗上升,一旦下降然后上升直到异常被抛出。 感觉垃圾收集器的工作频率不足以释放所有空间。

所以我尝试通过在函数中的某处添加GC.Collect()来手动启动垃圾收集器。它又有效了。即使有大图像。

我认为手动调用垃圾收集器既不是好的风格也不是高效的。任何人都可以提供有关如何解决这个问题的提示,而无需调用GC.Collect()?

3 个答案:

答案 0 :(得分:3)

最后,我认为问题是,垃圾收集器不知道图像有多大,因此无法计划合理的时间表。我找到了方法

Copy-item c:\tes\* *.txt c:\dest -recurse -force

这些方法告诉垃圾收集器何时分配和释放大型非托管对象,以便垃圾收集器可以更好地规划他的日程安排。

以下代码可以在没有任何内存问题的情况下运行:

<div style="overflow:scroll;"> </div>

答案 1 :(得分:2)

From where IImage parameter come? Dispose it after you finish with it.

So I tried to start the garbage collector manually by adding GC.Collect() somewhere in the function. And it works again. Even with the large images.

Image implements finalizer, if you don't dispose them. It will make those instances to live more than one GC cycles. Probably that's your issue.

Finalizer is the last point it can release unmanaged (managed too) resources if developer don't call the Dispose. When you call the Dispose it Supress the finalization and it will make them reachable for GC straight away.

can see the memory consumption go up, once go down and then go up till the exception is thrown. It feels like the garbage collector works not often enough to free all the space.

This is not quite right normally. But might be possible when you open/close images frequently and finalization queue is growing up.

Here is a good article for you : The Dangers of the Large Object Heap...

答案 2 :(得分:1)

当使用错误的工具进行工作时发生。视频实际上不是一组位图 - 有更好的方法可以做到这一点。

上次我必须做的是使用Direct3d。有一个WPF集成,在那里设置位图非常容易。允许在视频流中进行大量操作;)然后将图像直接推入Direct3d表面。结束。

没有代码示例 - 抱歉。这是几年前我没有准备好代码。

相关问题