7

MemoryStream を複数回使用すると問題が発生します。

例:

For Each XImage As XImage In pdfDocument.Pages(pageCount).Resources.Images
   Dim imageStream As New MemoryStream()
   XImage.Save(imageStream, System.Drawing.Imaging.ImageFormat.Jpeg)

   ' some further processing

   imageStream.Close()
   imageStream.Dispose()    
Next

このコードは、PDF ファイルのページ上の画像を循環します。ファイルには最大 cca 500 ページ、各ページに 5 つの画像があるとします。それは何千もの反復につながります。問題は、MemoryStream が解放されず、メモリ不足の例外が発生することです。XImage は通常、約 250 kB です。

ここでは Aspose.PDF ライブラリを使用して PDF を操作しています (XImage はこのライブラリのクラスです) が、問題ではありません。新しい MemoryStream を作成し、ダミーのビットマップを保存するだけの簡単な例を作成しようとしました。それは同じ問題につながります。

また、MemoryStream ではなく FileStream を使用しようとしましたが、同じように動作します。

どんな助けでも感謝します。

ありがとう

ジリ

4

1 に答える 1

21

ストリームからのメモリが解放されます。あなたに約束します。本当にそうです。

解放されないのは、そのメモリが以前占有していたアプリケーションのアドレス空間です。コンピューターで使用できる RAM は十分にありますが、特定のアプリケーションは、アドレス テーブル内にこれ以上割り当てる場所が見つからないため、クラッシュします。

制限に達した理由は、MemoryStream が成長するにつれてバッファーをリサイクルするためです。データを保持するために内部で byte[] を使用し、配列はデフォルトで特定のサイズに初期化されます。ストリームへの書き込み時に配列のサイズを超えると、ストリームは倍加アルゴリズムを使用して新しい配列を割り当てます。その後、古いアレイから新しいアレイに情報がコピーされます。この後、古い配列は収集されますが、圧縮されません(デフラグされたと考えてください)。その結果、プログラムの仮想アドレス テーブルに穴ができ、MemoryStream バッファーに対して十分な大きさではなくなります。1 つの MemoryStream が複数の配列を使用する可能性があり、その結果、合計アドレス空間に相当する複数のメモリ ホールが発生し、ソース データよりもはるかに大きくなる可能性があります。

私の知る限り、現時点では、ガベージ コレクターに強制的にメモリ アドレス空間を圧縮させる方法はありません。したがって、解決策は、最大の画像を処理できる大きなブロックを割り当て、同じブロックを何度も再利用して、到達できないメモリ アドレスにならないようにすることです。

このコードの場合、これは、ループの外側で MemoryStream を作成し、整数をコンストラクターに渡して、適切なバイト数に初期化することを意味します。これにより、アプリケーションが 1 つのバイト配列から別のバイト配列にデータを頻繁にコピーすることに突然時間を費やさなくなるため、パフォーマンスが大幅に向上することもわかります。

Using imageStream As New MemoryStream(307200) 'start at 300K... gives you some breathing room for larger images
    For Each XImage As XImage In pdfDocument.Pages(pageCount).Resources.Images

       'reset the stream, but keep using the same memory
       imageStream.Seek(0, SeekOrigin.Begin)
       imageStream.SetLength(0)

       XImage.Save(imageStream, System.Drawing.Imaging.ImageFormat.Jpeg)

       ' some further processing
   
    Next
End Using
于 2013-06-25T20:16:35.787 に答える