Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/339.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 垃圾收集器在处理大图像时速度太慢_C#_Memory Management_Memory Leaks_Garbage Collection_Dispose - Fatal编程技术网

C# 垃圾收集器在处理大图像时速度太慢

C# 垃圾收集器在处理大图像时速度太慢,c#,memory-management,memory-leaks,garbage-collection,dispose,C#,Memory Management,Memory Leaks,Garbage Collection,Dispose,我正在使用Emgu OpenCV从网络摄像头抓取图像,并希望使用WPFImageControl将其可视化。 因此,我需要将图像从Mat转换为与image控件兼容的内容。所以我从Emgu的例子中选了这门课: public static class BitmapSourceConvert { /// <summary> /// Delete a GDI object /// </summary> /// <param name="o"&g

我正在使用Emgu OpenCV从网络摄像头抓取图像,并希望使用WPF
Image
Control将其可视化。
因此,我需要将图像从
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;
        }
    }
}
公共静态类BitmapSourceConvert
{
/// 
///删除GDI对象
/// 
///要删除的GDI对象的poniter
/// 
[DllImport(“gdi32”)]
私有静态外部intdeleteObject(IntPtr o);
/// 
///将IImage转换为WPF BitmapSource。结果可用于Image.Source的Set属性
/// 
///Emgu CV图像
///等效位图源
公共静态位图源到位图源(IImage图像)
{
使用(System.Drawing.Bitmap源=image.Bitmap)
{
IntPtr ptr=source.GetHbitmap();//获取Hbitmap
BitmapSource bs=System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
ptr,
IntPtr.Zero,
Int32Rect.Empty,
System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
DeleteObject(ptr);//释放HBitmap
返回bs;
}
}
}
这就像一个小图像的魅力(例如640x480)。当使用任务管理器时(我在Windows 8上),我看到使用的内存在增加和减少。很好

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

因此,我尝试通过在函数中的某个位置添加GC.Collect()来手动启动垃圾收集器。它又起作用了。即使是大图像


我认为手动调用垃圾收集器既不是好的风格,也不是好的性能。任何人都可以在不调用GC.Collect()的情况下给出如何解决此问题的提示吗?

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

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


没有代码示例-抱歉。这是几年前的事了,我还没有准备好代码。

IImage参数从哪里来?用完后再处理

因此,我尝试通过添加 GC.Collect()位于函数中的某个位置。它又起作用了。即使 大图像

映像实现终结器(如果您不处理它们)。它将使这些实例的生命周期超过一个GC周期。这可能是你的问题

如果开发人员不调用Dispose,Finalizer是最后一个可以释放非托管(也托管)资源的点。当您调用Dispose时,它会阻止终结,并使GC可以立即访问它们

可以看到内存消耗上升,一次下降,然后上升到 异常被抛出。感觉垃圾收集器不起作用 通常足够释放所有空间

这通常是不对的。但当您频繁地打开/关闭图像并且正在形成最终确定队列时,这可能是可能的


这里有一篇好文章给你:…

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

GC.AddMemoryPreasure(long bytesAllocated)
GC.RemoveMemoryPreasure(long bytesAllocated)
这些方法告诉垃圾收集器何时分配和释放大型非托管对象,以便垃圾收集器能够以更好的方式规划其时间表

以下代码工作时没有任何内存问题:

    public static BitmapSource ToBitmapSource(IImage image)
    {
        using (System.Drawing.Bitmap source = image.Bitmap)
        {
            IntPtr ptr = source.GetHbitmap(); //obtain the Hbitmap
            long imageSize = image.Size.Height*image.Size.Width*4; // 4 bytes per pixel
            GC.AddMemoryPressure(imageSize);
            BitmapSource bs = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                ptr,
                IntPtr.Zero,
                Int32Rect.Empty,
                System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());

            DeleteObject(ptr); //release the HBitmap
            GC.RemoveMemoryPressure(imageSize);
            return bs;
        }
    }

谢谢你,汤姆。我认为你抓取和想象是对的。但在这里,我想用OpenCV对帧进行一些图像处理。所以我需要它们作为
Mat
。你的问题不清楚。无论如何,没有必要创建garbate。它们大小都一样。重复使用它们。不创建新位图;)Crystal ball说您永远不会调用IImage.Dispose()。是的,GC.Collect()将隐藏该问题。谢谢@CharithJ。这篇文章很有趣,帮助我更好地理解我的问题。但由于我使用的图像总是相同的大小,我不认为这正是我的问题。我想了些什么,并将提供一个答案。