内存泄漏,但在哪里?

时间:2014-09-01 13:55:03

标签: c# wpf memory-leaks

我无法理解这里泄漏的是什么

using GDI = System.Drawing;

public partial class MainWindow : Window
{
    [DllImport("gdi32.dll")]
    private static extern bool DeleteObject(IntPtr obj);

    public MainWindow()
    {
        InitializeComponent();

        var timer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(50) };
        timer.Tick += (s, a) =>
        {
            using (var bitmap = new GDI.Bitmap(1000, 1000))
            {
                var hbitmap = bitmap.GetHbitmap();
                var image = Imaging.CreateBitmapSourceFromHBitmap(hbitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
                image.Freeze();
                DeleteObject(hbitmap);
            }
        };
    timer.Start();
}

bitmap?弃置。 hbitmap?删除。 image?冻结,它不是IDisposable

事实是,这个应用程序会崩溃(在运行约20秒后在我的电脑上)

  

未处理的类型' System.OutOfMemoryException'发生在System.Drawing.dll

中      

其他信息:内存不足。

有什么想法吗?

2 个答案:

答案 0 :(得分:6)

据我所知,没有泄密。问题是你快速分配大C#对象并且垃圾收集器太迟了?

以下是一些相关主题:

Avoiding OutOfMemoryException during large, fast and frequent memory allocations in C#

这里有用的帖子:

Garbage Collection not happening even when needed

如果您踢GC.Collect(代数为0..3),您的内存消耗将被修复:

    while (true)
    {
        Thread.Sleep(5);

        using (var bitmap = new GDI.Bitmap(1000, 1000))
        {
            var hbitmap = bitmap.GetHbitmap();
            var image = Imaging.CreateBitmapSourceFromHBitmap(hbitmap, IntPtr.Zero, Int32Rect.Empty,
                BitmapSizeOptions.FromEmptyOptions());

            image.Freeze();


          DeleteObject(hbitmap);
        }

        Console.WriteLine("Current memory consumption" + GC.GetTotalMemory(false));
        GC.Collect(3);
    }

并输出:

Current memory consumption156572
Current memory consumption156572
Current memory consumption156572
Current memory consumption156572

真正的问题是GC不知道你的非托管分配,即使你释放它们。你需要增加内存压力,让GC了解它:

 var width = 1000;
                var height = 1000;

                using (var bitmap = new GDI.Bitmap(width, height))
                {
                    var hbitmap = bitmap.GetHbitmap();
                    var allocatedSize = width*height*4; // each pixel takes ~4 bytes?!
                    GC.AddMemoryPressure(allocatedSize);

                    var image = Imaging.CreateBitmapSourceFromHBitmap(hbitmap, IntPtr.Zero, Int32Rect.Empty,
                        BitmapSizeOptions.FromEmptyOptions());

                    image.Freeze();


                    DeleteObject(hbitmap);
                    GC.RemoveMemoryPressure(allocatedSize);
                }

让GC了解潜在的非托管内存有助于确保GC在正确的位置启动。

答案 1 :(得分:2)

垃圾收集器可能没有足够快地释放配置的位图。您每20秒创建400个1000 * 1000位图,这可能会消耗高达1.6GB的内存。也许尝试添加第二个计时器,每隔1000毫秒运行一次,调用GC.Collect()。