c # picturebox memória liberando problema
-
11-09-2019 - |
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!
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.