В общем, есть окно, где есть комбобокс с десятками ссылок на картинку весом ~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.
Хм...
Помог вот этот ответ.
Оказывается я должен был вызывать 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 мб.
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Виртуальный выделенный сервер (VDS) становится отличным выбором
У меня есть файл в котором есть начало считывания строкового значения C1 00 00 00 (193 офсет) и кол-во строк 0F 00 00 00 (15), строки разделяются 0x00 + 8 левых...
Для вывода картинки в WPF я конвертирую иконку от файла в формате bitmap в формат, который будет отображаться в контролеВот код