Pergunta

Eu sou um Newby em C #. Eu tenho que atualizar repetidamente uma caixa de imagem GUI em um segmento de trabalho. A imagem é adquirida a partir de uma sondagem câmera um motorista com um método GetImage que retrives a imagem a ser exibida. Mesmo se eu alocar o bitmap usando a diretiva "usando" e chamar explicitamente G.C, a memória parece nunca ser desalocada.

O segmento de trabalho é algo como isto:

   while (true)
    {
        // request image with IR signal values (array of UInt16)
        image = axLVCam.GetImage(0);
        lut = axLVCam.GetLUT(1);
        DrawPicture(image, lut);
        //GC.Collect();

    }

Enquanto o método DrawPicture é algo como

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

Problemas surge com o

= pic.Image System.Drawing.Image.FromHbitmap (bmp.GetHbitmap ());

Na verdade comentando essa linha de código, coleta de lixo funciona como seria. Melhor, o problema parece estar com

System.Drawing.Image.FromHbitmap (bmp.GetHbitmap ())

Algum conselho para resolver este vazamento de memória?

Muito obrigado!

Foi útil?

Solução

implementos Image IDisposable, então você deve chamar Dispose em cada instância Image que você criar, quando não é mais necessária. Você poderia tentar substituir esta linha em seu código:

pic.Image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());

Com este:

if (pic.Image != null)
{
    pic.Image.Dispose();
}
pic.Image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());

Isto irá desfazer a imagem anterior (se houver) antes de o novo é atribuído.

Outras dicas

A coisa é, você está fazendo um bitmap GDI de bmp com GetHbitmap, que de acordo com MSDN:

Você é responsável por chamar o método GDI DeleteObject à livre memória usada pelo objeto GDI bitmap.

Em seguida, o método FromHbitmap faz uma cópia do bitmap GDI; para que você possa liberar o bitmap GDI entrada usando o método GDI DeleteObject imediatamente depois de criar a nova imagem.

Então, basicamente, eu acrescentaria:

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

Não tenho a certeza se você precisa do bitmap GDI para executar algum tipo de transformação. No caso de você não pode apenas atribuir o bitmap para a propriedade de imagem do seu PictureBox, e ignorar a primeira solução:

// 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;

Existem várias maneiras de liberar uma imagem de Pbox. Eu recomendo fortemente a forma como é que não use pbox.Image = Image.FromFile.... Se você não usar FileStream e você quiser lê-lo do uso arquivo de classe bitmap. Como esta:

Bitmap bmp = new Bitmap(fileName);
pbox.Image = bmp; // notice that we used bitmap class to initialize pbox.

... e então você deseja liberar o arquivo de imagem bmp.Dispose();
Agora você pode apagar, mover ou o que quiser para o arquivo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top