在前篇文章[Cognitive] 在C#中使用Emgu.CV進行簡易的人臉辨識中,遇到了一個棘手的問題
就是在程式碼執行的過程中,記憶體會不斷的增加,即使使用了PictureBox.Image = null; 或是PictureBox.Image.Dispose() 都沒有用
原來問題是出在GetHbitmap這個方法上面
在PictureBox放入圖片的方式中,可以透過圖檔路徑,或是圖片的串流資料將圖片放入到PictureBox控制項中,如下面的程式碼所示
// 透過圖檔路徑將圖片放入到PictureBox控制項中
PictureBox.Image = Image.FromFile("C\\TEST.jpg");
// 透過圖片的串流物件將圖片放入到PictureBox控制項中
PictureBox.Image = Image.FromStream(objStream);
上面放入圖片的作法,雖然說會增加主機記憶體的使用量,但是只要能夠將Image屬性指定為null,或是進行Dispose,就可以有效的釋放記憶體,避免記憶體的佔用,如下面的程式碼所示
// 如果圖片的屬性不為null, 就釋放掉Image屬性的物件,並釋放出記憶體的使用
if (PictureBox.Image != null)
{
PictureBox.Image.Dispose();
}
但是如果在載入圖檔時所使用的方法是FromHbitmap(),那就完全不是這麼一回事了
不論是null,或是Dispose,對於釋放記憶都是完全沒有用處
不論是null,或是Dispose,對於釋放記憶都是完全沒有用處
為什麼?
簡單來說,因為bitmap是GDI+的物件,所以使用一般釋放記憶體的方式對於bitmap是無效的
要能夠成功的釋放GDI+物件所佔用的記憶體,就還是必須要使用Windows GDI元件,才能有效的釋放掉bitmap所使用的記憶體
使用的方式也很簡單,加上幾行程式碼就可以了
// 引用Windows GDI元件,並調用DeleteObject的方法
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
public void BindBitmapToPicture()
{
// 將Bitmap物件轉換為平台指標
IntPtr gdibitmap = myBitmap.Bitmap.GetHbitmap();
// 將bitmap放入至PictureBox的Image屬性
PictureBox.Image = Image.FromHbitmap(gdibitmap);
// 進行Bitmap資源的釋放
DeleteObject(gdibitmap);
}
這樣就可以很有效的釋放記憶體的使用了