2009-12-02 14 views
6

Ich bin ein Newby in C#. Ich muss ein GUI-Bildfeld in einem Worker-Thread wiederholt aktualisieren. Das Bild wird von einer Kamera erfasst, die einen Treiber mit einer GetImage-Methode abfragt, die das anzuzeigende Bild abruft. Selbst wenn ich die Bitmap mit der Direktive "using" zuteile und G.C explizit anrufe, scheint der Speicher nie freigegeben zu werden.C# picturebox Speicherfreigabe Problem

der Arbeiter-Thread ist etwa wie folgt:

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

    } 

Während die DrawPicture Methode

so ähnlich ist
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()); 
    } 
} 

Probleme ergibt sich bei der

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

In der Tat kommentieren diese Codezeile Garbage Collection so wie es wäre. Besser, scheint das Problem mit

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

Jeder Beratung, um dieses Speicherleck zu lösen?

Vielen Dank!

Antwort

12

Image implementiert IDisposable, so sollten Sie Dispose auf jeder Image Instanz aufrufen, die Sie erstellen, wenn sie nicht mehr benötigt wird. Sie könnten versuchen, diese Zeile im Code zu ersetzen:

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

mit diesem:

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

Dies wird das vorherige Bild entsorgen (falls vorhanden), bevor die neue zugeordnet ist.

+0

Das Problem ist, dass er kein GDI-Objekt entsorgt. –

+0

@ Yannick: guter Punkt. Ich kann mir vorstellen, dass beide Probleme Probleme für den Garbage Collector verursachen. –

+0

In der Tat verfügen Sie durch den Aufruf von Dispose on Image über nicht verwaltete Ressourcen, die beim Aufruf von 'FromHbitmap()' zugewiesen werden. Die aktuelle Lösung ignoriert jedoch das nicht verwaltete GDI-Objekt, das beim Aufruf von "GetHbitmap()" erstellt wird. –

7

Die Sache ist, machst du einen GDI-Bitmap von bmp mit GetHbitmap, die Msdn nach:

Sie sind verantwortlich die GDI DeleteObject-Methode für den Aufruf des Speicher durch die GDI verwendet zu befreien Bitmap-Objekt.

Dann erstellt die FromHbitmap-Methode eine Kopie der GDI-Bitmap; So können Sie die eingehende GDI-Bitmap mit der GDI DeleteObject-Methode sofort nach dem Erstellen des neuen Image freigeben.

Also im Grunde möchte ich hinzufügen:

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

Ich bin nicht sicher, ob Sie die GDI-Bitmap eine Art von Transformation durchzuführen. Falls Sie Sie nicht können zuweisen nur die Bitmap in der Bild-Eigenschaft des PictureBox, und ignorieren die frühere Lösung:

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

Es gibt mehrere Möglichkeiten, von pbox ein Bild zu veröffentlichen.Ich empfehle dringend den Weg ist, dass nicht pbox.Image = Image.FromFile... verwenden. Wenn Sie FileStream nicht verwenden und aus der Datei lesen möchten, verwenden Sie die BitMap-Klasse. Wie folgt aus:

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

... und dann wollen Sie das Bild Release-Datei bmp.Dispose();
Jetzt können Sie löschen, verschieben oder was auch immer Sie in die Datei möchten.