проблема освобождения памяти в картинках c # - PullRequest
6 голосов
/ 02 декабря 2009

Я новичок в C #. Я должен многократно обновлять графическое окно графического интерфейса в рабочем потоке. Изображение получается с камеры, опрашивающей драйвер с помощью метода GetImage, который извлекает изображение для отображения. Даже если я выделю растровое изображение с помощью директивы «using» и явно вызову G.C, память никогда не будет освобождена.

Рабочий поток выглядит примерно так:

   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 ())

Какой-нибудь совет, чтобы решить эту утечку памяти?

Большое спасибо!

Ответы [ 3 ]

12 голосов
/ 02 декабря 2009

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());

Это позволит удалить предыдущее изображение (если оно есть) до назначения нового.

8 голосов
/ 02 декабря 2009

Дело в том, что вы создаете растровое изображение GDI bmp с GetHbitmap, которое в соответствии с msdn:

Вы несете ответственность за вызов GDI DeleteObject метод для освобождения память, используемая растровым объектом 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;
3 голосов
/ 22 февраля 2011

Существует несколько способов освободить изображение из 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();
Теперь вы можете удалить, переместить или что угодно в файл.

...