2009-12-02 22 views
6

私はC#でnewbyです。私は繰り返しワーカースレッドでGUIの画像ボックスを更新する必要があります。イメージは、表示されるイメージを取得するGetImageメソッドを使用してドライバをポーリングするカメラから取得されます。たとえ "using"という命令を使ってビットマップを割り当てて、明示的にG.Cを呼び出すとしても、メモリは決して割り当て解除されないようです。 DrawPictureメソッドはC#pictureboxメモリ解放問題

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で発生し

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

    } 

ワーカースレッドがこのようなものです.Image.FromHbitmap(bmp.GetHbitmap());

実際には、コード行にコメントすると、ガベージコレクションは正常に動作します。 より良い、問題は、このメモリリークを解決するために

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

何かアドバイスであると思われますか?

ありがとうございます!

答えて

12

ImageIDisposableを実装しているため、作成した各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オブジェクトを処分していないことです。 –

+0

@ヤニック:良い点。両方の問題がガベージコレクタに問題を引き起こすと思います。 –

+0

実際、Dispose on Imageを呼び出すと、 'FromHbitmap()'を呼び出すときに割り当てられるアンマネージドリソースを処分できます。しかし、現在のソリューションでは、 'GetHbitmap()'を呼び出すときに作成されるアンマネージGDIオブジェクトは無視されます。 –

7

事はあなたがMSDNによるとGetHbitmap、とbmpのGDIビットマップを作っている、次のとおりです。

あなたはGDIが使用する メモリを解放するために GDI DeleteObjectのメソッドを呼び出すための責任がありますビットマップオブジェクト。

次に、FromHbitmapメソッドはGDIビットマップのコピーを作成します。新しいイメージを作成した直後に、GDI DeleteObjectメソッドを使用して、着信GDIビットマップを解放することができます。

だから、基本的に私は追加します。あなたはある種の変換を実行するために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); 

は私はわかりませんよ。あなたはちょうどあなたのPictureBoxの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();
をリリースしたい今、あなたは、削除、移動したり、ファイルに好きなことができます。

関連する問題