内存泄漏,但在哪里

本文关键字:在哪里 泄漏 内存 | 更新日期: 2023-09-27 18:20:10

我不明白这里泄漏了什么

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.Drawing.dll 中发生类型为"System.OutOfMemoryException"的未处理异常

附加信息:内存不足。

有什么想法吗?

内存泄漏,但在哪里

据我所知,没有发生泄漏。问题是你分配大C#对象的速度很快,垃圾收集器启动得太晚了?

以下是一些相关主题:

在C#中避免大规模、快速和频繁的内存分配过程中出现OutOfMemoryException

这里有一个有用的线程:

即使在需要时也不会进行垃圾收集

如果你启动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在正确的位置发挥作用。

可能是垃圾回收器释放已处理位图的速度不够快。您每20秒创建400个1000*1000位图,这可能会消耗高达1.6GB的内存。也许可以尝试添加一个每1000毫秒运行一次的第二个计时器来调用GC.Collect().