Domanda

Sono un newby in C #. Devo aggiornare ripetutamente una casella di immagine GUI in un thread di lavoro. L'immagine viene acquisita da una fotocamera polling un driver con un metodo che GetImage retrives l'immagine da visualizzare. Anche se allocare la bitmap direttiva using "usando" e chiamare esplicitamente G.C, la memoria sembra essere mai deallocato.

Il thread di lavoro è qualcosa di simile:

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

    }

Mentre il metodo DrawPicture è qualcosa di simile

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

I problemi si pone con il

  

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

In realtà commentando che riga di codice, raccolta dei rifiuti funziona come farebbe. Meglio, il problema sembra essere con

  

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

Qualche consiglio per risolvere questo problema di memoria?

Grazie mille!

È stato utile?

Soluzione

Image implementa IDisposable, così si dovrebbe chiamare Dispose su ogni istanza Image che si crea, quando non è più necessario. Si potrebbe provare a sostituire questa riga nel codice:

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

Con questa:

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

Questa disporrà l'immagine precedente (se presente) prima di quello nuovo viene assegnato.

Altri suggerimenti

La cosa è, si sta facendo una bitmap GDI di bmp con GetHbitmap, che secondo MSDN:

  

L'utente è responsabile per chiamare il   GDI metodo per liberare il DeleteObject   memoria utilizzata dall'oggetto bitmap GDI.

Poi il metodo FromHbitmap esegue una copia della bitmap GDI; in modo da poter liberare la bitmap GDI in entrata utilizzando il metodo GDI DeleteObject subito dopo aver creato la nuova immagine.

Quindi, fondamentalmente vorrei aggiungere:

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

Non sono sicuro se è necessario la bitmap GDI per eseguire qualche tipo di trasformazione. Nel caso in cui non si può semplicemente assegnare il bitmap alla proprietà Immagine del PictureBox, e ignorare la prima soluzione:

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

Ci sono diversi modi per rilasciare un'immagine da pbox. Consiglio vivamente il modo è che non usano pbox.Image = Image.FromFile.... Se non si utilizza FileStream e si desidera leggere da utilizzare file di classe bitmap. In questo modo:

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

... e poi si desidera rilasciare il file immagine bmp.Dispose();
Ora è possibile eliminare, spostare o quello che volete al file.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top