2009-05-16 10 views
1

私はビットマップを取得し、GZipStreamを使用して圧縮し、メモリ上のソケットで送信するアプリケーションを持っています。私はImageクラスは、さまざまなコーデックを節約する方法でメモリリークについては、多くの話題を発見した古き良き情報スーパーハイウェイの周りBitmap.Save、巨大なメモリリーク

frame.Save(inStream, jpegCodec, parameters); 

ブラウズ:私は次の行に汚いscumbagメモリリークを突き止めています。問題はそこに私が見つけることができる修正が実際にはないということです。次のようにだから私の質問は以下のとおりです。

  1. この
  2. がどのように私はここに、この

を修正することができます原因は何リークが配置されている私のFrameStreamクラスで私の完全なwrite()メソッドです。

/// <summary> 
    /// Writes a frame to the stream 
    /// </summary> 
    /// <param name="frame">The frame to write</param> 
    public void Write(Bitmap frame) { 
     using (EncoderParameter qualityParameter = new EncoderParameter(Encoder.Quality, 50L)) { 
      using (EncoderParameters parameters = new EncoderParameters(1)) { 
       parameters.Param[0] = qualityParameter; 

       ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders(); 
       ImageCodecInfo jpegCodec = null; 

       foreach (ImageCodecInfo codec in codecs) { 
        if (codec.MimeType == "image/jpeg") { 
         jpegCodec = codec; 
         break; 
        } 
       } 

       using (MemoryStream inStream = new MemoryStream()) { 
        frame.Save(inStream, jpegCodec, parameters); // HUUUGE Memory Leak 
        Byte[] buffer = new Byte[inStream.Length]; 
        inStream.Read(buffer, 0, buffer.Length); 

        using (MemoryStream outStream = new MemoryStream()) { 
         using (GZipStream gzipStream = new GZipStream(outStream, CompressionMode.Compress)) { 
          gzipStream.Write(buffer, 0, buffer.Length); 
         } 

         Byte[] frameData = outStream.ToArray(); 
         Byte[] packet = new Byte[15 + frameData.Length]; 
         Byte[] frameLength = BitConverter.GetBytes(frameData.Length); 

         Array.Copy(frameLength, 0, packet, 0, frameLength.Length); 
         Array.Copy(frameData, 0, packet, 15, frameData.Length); 

         m_Socket.Send(packet); 
        } 
       } 
      } 
     } 
    } 
+0

あなたはリフレクターで自分自身を見ましたか? –

答えて

4

CLRプロファイラの下でコードを実行して、漏れの原因を突き止めることをお勧めします。これは、コンパクトなフレームワークの観点から見たBitmapクラスに関する興味深いリンクです。それがどのタイプの管理オブジェクト(管理されていないリソースさえも)であれば、管理されていないハンドルが漏れている管理されたタイプに起因していない限り、漏れがどこにあるかを見ることができます。フレームワークコードの場合、おそらくリフレクションとP/Invokeを使用して回避することができます。

たとえば、Iconタイプでは、状況によってはWin32 HICONがリークします。この問題を回避するには、Iconによって公開されているハンドルを使用してDeleteObject関数をインポートすることによってHICONを手動で処理することです。

0

私はソケットについてよく分かりません。しかし、Imageクラスでメモリリークを止める方法の1つは、ビットマップをフリーズすることです。うまくいけば、this postはさらに詳しい情報を提供するかもしれません。 MemoryStream.Disposeが失敗することはありますか?これにより、メモリリークが発生します。

0

Graphicsオブジェクトの.Dispose()メソッドを呼び出していますか?そのになり、メモリリークが発生します。編集:バイト[]を書いたら、Bitmapオブジェクトの.Dispose()にクリアされます。

+0

frame.Save(..)をコメントアウトすると、メモリリークはなく、すべてのグラフィックスオブジェクトが破棄され、説明されます。私の周りを検索して、bitmap.saveメモリリークは、msftというフレームワークのバグとしてマークされていました。何かを探している修正プログラムがあるかどうかわからない –

+0

@David:質問にその情報を追加して、混乱を避けることができます。 –

2

処理後、廃棄後にビットマップをnullに設定する必要があります。

また、あなたは(それが高価な操作であっても)ビットマップの処分後にガベージコレクタを起動することもできます。GC.Collect();

ビットマップは、アンマネージリソースを保持している - GCは「ボールに」常にではないとこれら。 http://blog.opennetcf.com/ctacke/PermaLink,guid,987041fc-2e13-4bab-930a-f79021225b74.aspx

+0

を考えてみると、たぶん卑劣でスレッドを使用して保存を行うことができます。スレッドが終了すると、特にリソースを保持しているオブジェクトの廃棄とともに、漏れたメモリを再利用できるはずです。私は間違っている可能性がありますが、他のすべてが失敗したら試してみる価値があります。 – Demi

3

すべてのアイデアや思考、その他多数の方法を試してみてください。私は最終的にシンプルを試してみました:

using (frame) { 
    frame.Save(outStream, jpegCodec, parameters); 
} 

よく、これは働いていたとメモリリークが固定されている..私は強制的に、ガベージコレクタを呼び出す手動でビットマップを配置し、P /呼び出しDeleteObjectの、働いていた何を使ってますが、使ってみましたusingステートメントがしました。だから、これは私が不足していることを使用している文章の中で、どのようなことが起こっているのか不思議に思っています....

+2

これは単にDisposeを呼び出します。上記のWriteメソッドをどのように呼び出しているかを私たちに知らせるのに十分なコードは実際には表示されていません。ビットマップを実際に処分していないと思われます。 –

+0

上記のコードでは、m_Socket.Send(...)の後のframe.Dispose()行を削除しましたが、フレームのdisposeを呼び出してもテストに違いはありませんでしたが、まだ多くのメモリが割り当てられていました –

+0

ターンさらなる調査の後、アプリ内のソケットがキューに入れられるビットマップの数に追いつくのに十分な速さでパケットを送信することができないので、待ち行列に入れられたビットマップがメモリに蓄積される –