Утечка памяти при работе с графикой

163
22 ноября 2018, 20:30

В общем, есть окно, где есть комбобокс с десятками ссылок на картинку весом ~2 мб и разрешением 5037x3657.

Каждое перелистывание картинок добавляет используемое озу к программе, вплоть до 2 ГБ...

Картинки я нигде не кеширую.

VM у меня при каждом изменении значения в ComboBox запрашивает Drawing.Image из класса:

  public ImageInfo CurrentImageInfo
    {
        get => _currentImageInfo;
        set
        {
            _currentImageInfo = value;
            OnPropertyChanged(nameof(CurrentImageInfo));
            try
            {
                using (var bitmap = (Bitmap)CurrentImageInfo.GetMarkupedImage())
                {
                    ImageSrc = BitmapToImageSource(bitmap);
                }
            }
            catch (Exception e)
            {
                LogMessage += "\n" + e;
            }
            ImageSource BitmapToImageSource(Bitmap bitmap)
            {
                return System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                     bitmap.GetHbitmap(),
                     IntPtr.Zero,
                     Int32Rect.Empty,
                     BitmapSizeOptions.FromEmptyOptions());
            }
        }
    }
 public Image GetMarkupedImage()
    {
        Image image;
        int x;
        int y;
        using (var srcImage = GetImageCopy())
        {
            image = MarkupDrawer.CreateImageWithBorder(srcImage, out x, out y);
        }
        using (var graphic = Graphics.FromImage(image))
        {
            foreach (var person in Persons)
            {
                var newRec = MarkupDrawer.ScaleMarkup(person.Rectangle, x, y);
                MarkupDrawer.DrawMarkup(graphic, image, person.ToString(), newRec);
            }
        }
        return image;
    }
    Image GetImageCopy()
    {
        var memoryStream = new MemoryStream();
        File.OpenRead(FilePath).CopyTo(memoryStream);
        return Image.FromStream(memoryStream);
    }

Вроде, ничего криминального не вижу в коде.

ImageSource не обладает методом Dispose.

Answer 1

Хм...

Помог вот этот ответ.

Оказывается я должен был вызывать WinApi функцию DeleteObject и передавать ей на вход bitmap.GetHbitmap() .

Т.е правильный код без утечек выглядит так:

   public ImageInfo CurrentImageInfo
    {
        get => _currentImageInfo;
        set
        {
            _currentImageInfo = value;
            OnPropertyChanged(nameof(CurrentImageInfo));
            try
            {
                using (var bitmap = (Bitmap)CurrentImageInfo.GetMarkupedImage())
                {
                  ImageSrc = BitmapToImageSource(bitmap);
                }
            }
            catch (Exception e)
            {
                LogMessage += "\n" + e;
            }
            BitmapSource BitmapToImageSource(Bitmap bitmap)
            {
                var bmpPt = bitmap.GetHbitmap();
                var bitmapSource=Imaging.CreateBitmapSourceFromHBitmap( bmpPt,IntPtr.Zero, Int32Rect.Empty,BitmapSizeOptions.FromEmptyOptions());
                bitmapSource.Freeze();
                NativeMethods.ReleaseHbitmap(bmpPt);
                return bitmapSource;
            }
        }
    }
    public static class NativeMethods
    {
        [DllImport("gdi32.dll",EntryPoint = "DeleteObject")]
        [return: MarshalAs(UnmanagedType.Bool) ]
        internal static extern bool ReleaseHbitmap(IntPtr value);
    }

После этого ОЗУ перестало уходить в потолок и держится в районе 250 мб.

READ ALSO
С# Как считать string из hex

С# Как считать string из hex

У меня есть файл в котором есть начало считывания строкового значения C1 00 00 00 (193 офсет) и кол-во строк 0F 00 00 00 (15), строки разделяются 0x00 + 8 левых...

216
Выдвигающиеся панели

Выдвигающиеся панели

Как на WPF можно реализовать выдвигающиеся панели

185
Как конвертировать, bitmap в ImageSource, пробую не получается

Как конвертировать, bitmap в ImageSource, пробую не получается

Для вывода картинки в WPF я конвертирую иконку от файла в формате bitmap в формат, который будет отображаться в контролеВот код

164
MVVM WPF обращение к объекту из другого окна

MVVM WPF обращение к объекту из другого окна

В очередной раз столкнулся с проблемой

164