1

新しいビットマップを作成し、「get」アクセサーを介して返そうとすると、メモリ不足の例外が発生します。Bitmap のサイズは 640x480 で、深さは Int32 です。

私の疑いは、C# ガベージ コレクターがこれらの古いビットマップを削除できないということです。これは、それらが私の変数へのアクセサーで返されているためです。2GB をはるかに超える空き容量があるので、この「小さい」イメージが大量のメモリを消費しているとは思えません。残念ながら、スレッド ロックの問題 (スレッド間で画像をロックする際の問題) により、ビットマップを新しくする必要があります。コードは次のとおりです。

public Bitmap LiveFrame { get { return GetFrame(500); } }

.....

private Bitmap GetFrame(int timeout)
{
   Bitmap ret = null;
   //CLEyeCameraGetFrame places image data into this._PrivateBitmap
   bool success = CLEyeCameraGetFrame(_Camera, _PtrBmpPixels, timeout);  

   if(success) 
     ret = new Bitmap(this._PrivateBitmap);
    return ret;
}

アンマネージ コードに関する注意: CLEyeCameraGetFrame はアンマネージ DLL 内にあります。コードの前半で Marshal.AllocHGlobal を使用して _PtrBmpPixels を割り当て、アプリを閉じるときに解放するまで触れません。_PtrBmpPixels は、IntPtr 引数 "scan0" を受け入れるコンストラクターを介して Bitmap _PrivateBitmap の作成に使用されました。したがって、_PtrBmpPixels が CLEyeCameraGetFrame を介して更新されるたびに、_PrivateBitmap も更新されます。

PcitureBox ビットマップを再利用する前に破棄することでこれを修正しようとしましたが、PictureBox の表示が壊れました。2 つの異なる PictureBox/ImageBox を更新する 2 つのスレッドがあります。

lock (_CameraLocker)
{
  if (_VideoPlaying)
  {
    try{
         if (pbLiveFeed.Image != null)
            pbLiveFeed.Image.Dispose();

         pbLiveFeed.Image = _Camera.LiveFrame;
         pbLiveFeed.Invalidate();
       }catch (Exception ex) { }
}

....

lock (_CameraLocker)
{
   try{
        if (ibProcessed.Image != null)
          ibProcessed.Image.Dispose();
        procImage = new Image<Bgra, Int32>(_Camera.LiveFrame);
        procImage.Draw(new Rectangle(10, 20, 20, 15), new Bgra(1.0, 1.0, 1.0, 1.0), 5);

        ibProcessed.Image = procImage;
      }catch (Exception ex) { }
}

ガベージ コレクションが原因でしょうか。get アクセサーから newed オブジェクトを返すのは安全ではないですか?

4

1 に答える 1

5

あなたの質問の唯一の本当の手がかりは、何が欠けているかです。「ビットマップを使用した後は必ず破棄する」と言ったことはありません。これは、.NET プログラミングでは簡単に見落とされがちですが、ビットマップを使用すると悩まされることになります。

Bitmap クラスは、 GDI+ によって作成されたアンマネージリソースの非常に小さなラッパー クラスです。実際のビットマップ ピクセルは、アンマネージ メモリに格納されます。これが、アンマネージ メモリ割り当てを解放する Dispose() メソッドがクラスにある理由です。ガベージ コレクターは、このメモリを自動的に解放するためにほとんど何もできません。Bitmap オブジェクトは小さすぎて、プログラムがアンマネージ メモリを消費する速度に追いつくのに十分な頻度でガベージ コレクションを誘発できません。オムカブームが結果です。

コードの残りの部分を見て、LiveFrame プロパティがどのように使用されているかを確認する必要があります。そして、返されたビットマップが破棄されていることを確認してください。たとえば、PictureBox.Image プロパティに割り当てた場合、割り当てる前に古い画像を破棄する必要があります。

于 2013-02-13T18:58:13.933 に答える