2009-12-02 74 views
6

我是C#中的一個newby。我必須重複刷新工作線程中的GUI圖片框。該圖像是從照相機中獲取的,該圖像通過GetImage方法來輪詢驅動程序,該方法回顧要顯示的圖像。即使我使用指令「using」分配位圖並顯式調用G.C,內存似乎也不會解除分配。c#picturebox內存釋放問題

工作者線程是這樣的:

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

任何建議來解決此內存泄漏?

非常感謝!

回答

12

Image implements IDisposable,所以你應該在你創建的每個Image實例上調用Dispose當它不再需要時。你可以嘗試在你的代碼替換該行:

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

有了這個:

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

這將處置以前的圖像(如果有的話)的新的分配之前。

+0

問題是他沒有配置GDI對象。 – 2009-12-02 09:44:39

+0

@Yannick:好點。我想象這兩個問題都會爲垃圾收集器產生問題。 – 2009-12-02 09:51:07

+0

事實上,通過調用Dispose on Image,您可以調用在調用'FromHbitmap()'時分配的非託管資源。然而,當前的解決方案忽略調用'GetHbitmap()'時創建的非託管GDI對象。 – 2009-12-02 09:56:57

7

的事情是,你正在做的bmp與GetHbitmap,其根據MSDN一個GDI位圖:

你是負責調用 GDI DeleteObject的方法來釋放由GDI使用的 內存位圖對象。

然後FromHbitmap方法複製GDI位圖;因此您可以在創建新映像後立即使用GDI DeleteObject方法釋放傳入的GDI位圖。

所以基本上我想補充:

[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屬性,而忽視了前者的解決方案:

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

有幾種方法可以從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();
現在你可以刪除,移動,或任何你想要的文件。