首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Imaging.CreateBitmapSourceFromHBitmap中的内存泄漏

Imaging.CreateBitmapSourceFromHBitmap中的内存泄漏
EN

Stack Overflow用户
提问于 2016-08-03 07:41:01
回答 2查看 385关注 0票数 0

我有下一个功能(制作截图)

代码语言:javascript
复制
[DllImport("gdi32.dll")]
    private static extern bool DeleteObject(IntPtr hObject);
    private Screen SavedScreen { get; } = Screen.PrimaryScreen;

    private BitmapSource CopyScreen()
    {
        try
        {
            BitmapSource result;
            using (
                var screenBmp = new Bitmap(SavedScreen.Bounds.Width, SavedScreen.Bounds.Height, PixelFormat.Format32bppArgb))
            {
                using (Graphics bmpGraphics = Graphics.FromImage(screenBmp))
                {
                    bmpGraphics.CopyFromScreen(SavedScreen.Bounds.X, SavedScreen.Bounds.Y, 0, 0, screenBmp.Size,
                        CopyPixelOperation.SourceCopy);
                    IntPtr hBitmap = screenBmp.GetHbitmap();

                    //********** Next line do memory leak
                    result = Imaging.CreateBitmapSourceFromHBitmap( hBitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
                    DeleteObject(hBitmap);
                }
            }
            return result;
        }
        catch (Exception ex)
        {
            //ErrorReporting ($"Error in CopyScreen(): {ex}");
            Debugger.Break();
            return null;
        }
    }

并且无法避免内存泄漏,这是调用Imaging.CreateBitmapSourceFromHBitmap的结果。当我在循环中调用这个函数时,这个内存泄漏对我来说非常重要。在WPF应用程序(Windows、c#)中调用

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-08-03 08:03:04

正如您已经知道的,您必须Dispose() screenBmp

您实际上是通过一个using语句调用它的,所以应该可以,但是我怀疑try/catch可能会干扰它。

您是否有机会移动try/catch,以便只包围CopyFromScreenCreateBitmapSourceFromHBitmap

从评论中

因为只有在using语句的结束大括号之后,您才确信screenBmp 可以释放,所以我在那里强制使用GC collect

代码语言:javascript
复制
GC.Collect(); 
return result;

而且,似乎没有漏水。

这是我的演示

代码语言:javascript
复制
class Program
{

    [DllImport("gdi32.dll")]
    private static extern bool DeleteObject(IntPtr hObject);
    private static Screen SavedScreen { get; } = Screen.PrimaryScreen;

    private static BitmapSource CopyScreen()
    {
        //try
        //{
        BitmapSource result;
        using (
            var screenBmp = new Bitmap(200, 100))
        {
            using (Graphics bmpGraphics = Graphics.FromImage(screenBmp))
            {
                bmpGraphics.CopyFromScreen(SavedScreen.Bounds.X, SavedScreen.Bounds.Y, 0, 0, screenBmp.Size,
                    CopyPixelOperation.SourceCopy);
                IntPtr hBitmap = screenBmp.GetHbitmap();
                bmpGraphics.Dispose();
                //********** Next line do memory leak
                result = Imaging.CreateBitmapSourceFromHBitmap(hBitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
                DeleteObject(hBitmap);
                //result = null;

            }
        }
        GC.Collect();
        return result;
        //}
        //catch (Exception ex)
        //{
        //    //ErrorReporting ($"Error in CopyScreen(): {ex}");
        //    Console.WriteLine(ex.Message);
        //    Debugger.Break();
        //    return null;
        //}
    }

    static void Main(string[] args)
    {
        for (int i = 0; i < 100000; i++)
        {
            Thread.Sleep(100);
            var test = CopyScreen();
        }
    }
}
票数 1
EN

Stack Overflow用户

发布于 2016-08-03 09:03:45

当您使用位图(屏幕大小)时,这意味着预期的数据大小大于85000字节。GC对这些大小的对象进行了不同的处理。这叫陆恭蕙。参见https://blogs.msdn.microsoft.com/maoni/2016/05/31/large-object-heap-uncovered-from-an-old-msdn-article/,它在4.5 https://blogs.msdn.microsoft.com/dotnet/2011/10/03/large-object-heap-improvements-in-net-4-5/中得到了改进,但问题仍然存在。使用高频计算巨大的对象会显著增加应用程序的内存使用量。有两个问题导致了它: 1) GC不能立即工作,它需要时间才能开始释放内存;2) LOH的碎片(请参阅第一篇文章),这就是为什么它没有被释放,这就是为什么您可以看到内存使用量增加了。

可能的解决方案: 1)使用服务器GC和一致GC;手动强制GC。很可能这不会有太大帮助。2)重用现有对象(分配内存),而不是一直在循环中创建新的位图和图形。3)切换到直接使用Windows,手动处理分配。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38737349

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档