Проблема с освобождением памяти в C# PictureBox
-
11-09-2019 - |
Вопрос
Я новичок в C#.Мне приходится неоднократно обновлять окно изображения графического интерфейса в рабочем потоке.Изображение получается с камеры, опрашивающей драйвер с помощью метода GetImage, который извлекает изображение для отображения.Даже если я выделю растровое изображение с помощью директивы using и явно вызову GC, память, похоже, никогда не будет освобождена.
Рабочий поток выглядит примерно так:
while (true)
{
// request image with IR signal values (array of UInt16)
image = axLVCam.GetImage(0);
lut = axLVCam.GetLUT(1);
DrawPicture(image, lut);
//GC.Collect();
}
Хотя метод DrawPicture похож на
public void DrawPicture(object image, object lut)
{
[...]
// We have an image - cast it to proper type
System.UInt16[,] im = image as System.UInt16[,];
float[] lutTempConversion = lut as float[];
int lngWidthIrImage = im.GetLength(0);
int lngHeightIrImage = im.GetLength(1);
using (Bitmap bmp = new Bitmap(lngWidthIrImage, lngHeightIrImage)) {
[...many operation on bitmap pixel...]
// Bitmap is ready - update image control
//SetControlPropertyThreadSafe(tempTxtBox, "Text", string.Format("{0:0.#}", lutTempConversion[im[160, 100]]));
//tempTxtBox.Text = string.Format("{0:00000}", im[160, 100]);
//System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
pic.Image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
}
}
Проблемы возникают с
pic.Image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
Фактически, комментируя эту строку кода, сбор мусора работает так, как и должен.Лучше, похоже, проблема в
System.Drawing.Image.FromHbitmap(bmp.GetHbitmap())
Есть какие-нибудь советы по устранению этой утечки памяти?
Большое спасибо!
Решение
Image
реализует IDisposable
, поэтому вам следует позвонить Dispose
на каждого Image
экземпляр, который вы создаете, когда он больше не нужен.Вы можете попробовать заменить эту строку в своем коде:
pic.Image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
С этим:
if (pic.Image != null)
{
pic.Image.Dispose();
}
pic.Image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
Это приведет к удалению предыдущего изображения (если оно есть) перед назначением нового.
Другие советы
Дело в том, что вы создаете растровое изображение GDI bmp
с GetHbitmap, который, согласно msdn:
Вы несете ответственность за вызов метода GDI DeleteObject, чтобы освободить память, используемую объектом Bitmap GDI.
Затем метод FromHbitmap создает копию растрового изображения GDI;поэтому вы можете освободить входящее растровое изображение GDI с помощью метода GDI DeleteObject сразу после создания нового изображения.
В общем, я бы добавил:
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
...
IntPtr gdiBitmap = bmp.GetHbitmap();
// Release the copied GDI bitmap
if (pic.Image != null)
{
pic.Image.Dispose();
}
pic.Image = System.Drawing.Image.FromHbitmap(gdiBitmap);
// Release the current GDI bitmap
DeleteObject(gdiBitmap);
Я не уверен, нужно ли вам растровое изображение GDI для выполнения какого-либо преобразования.Если вы этого не сделаете, вы можете просто назначить растровое изображение свойству Image вашего PictureBox и игнорировать прежнее решение:
// Since we're not using unmanaged resources anymore, explicitly disposing
// the Image only results in more immediate garbage collection, there wouldn't
// actually be a memory leak if you forget to dispose.
if (pic.Image != null)
{
pic.Image.Dispose();
}
pic.Image = bmp;
Есть несколько способов выпустить образ из pbox.Я настоятельно рекомендую, чтобы не использовать pbox.Image = Image.FromFile...
.Если вы не используете FileStream и хотите прочитать его из файла, используйте класс BitMap.Так:
Bitmap bmp = new Bitmap(fileName);
pbox.Image = bmp; // notice that we used bitmap class to initialize pbox.
...а затем вы хотите выпустить файл изображения bmp.Dispose();
Теперь вы можете удалить, переместить или сделать что угодно в файле.