時期尚早と思われるメモリ不足の例外が原因で、さまざまな .NET コンストラクトのメモリ使用量を綿密に調査してきました。特に、ラージ オブジェクト ヒープを断片化する傾向がある大きなオブジェクトは、時期尚早のメモリ不足の例外を引き起こします。少し驚くべき領域の 1 つは、.NET の画像クラス (ビットマップとメタファイル) です。
私たちが学んだことは次のとおりですが、検証するための MS ドキュメントを見つけることができませんでした。
(1) 圧縮されたラスター ファイル (JPG、PNG、GIF など) から Bitmap オブジェクトを作成すると、そのファイルの最大解像度で、完全に圧縮されていないピクセル配列のメモリが消費されます。したがって、たとえば、9000x3000 ピクセルの 5MB JPG は 9000x3000x3 バイト (24 ビット カラー、アルファなしと仮定) に拡張されるか、81MB のメモリが消費されます。正しい?
(1a) 元の圧縮形式も保存されているという証拠 (以下の 2b を参照) があります。この場合、実際には 86MB です。しかし、それは不明です...誰か知っていますか?
(2) Metafile オブジェクトを作成し、ラスター ファイル (JPG、PNG、GIF など) をそこに描画すると、圧縮ファイルのメモリのみが消費されます。したがって、9000x3000 ピクセルの 5MB の JPG をメタファイルに描画すると、約 5MB のメモリしか消費しません。正しい?
(2a) ラスター ファイルをメタファイル オブジェクトに描画するには、ビットマップをファイルと共に読み込み、ビットマップをメタファイルに描画するしかないようです。その巨大なビットマップ データを一時的にロードする (および関連するメモリの断片化を引き起こす) ことを伴わない、より良い方法はありますか?
(2b) ビットマップをメタファイルに描画すると、元の圧縮ファイルと同様のサイズの圧縮形式が使用されます。元の圧縮ファイルをビットマップに保存することでそれを行いますか? それとも、元の圧縮設定を使用して展開されたビットマップを再圧縮することによってそれを行いますか?
(3) 当初、大きな (>85KB) イメージ オブジェクトはラージ オブジェクト ヒープに配置されると想定していました。実際、そうではないようです。むしろ、各ビットマップと各メタファイルは、実際のデータを含むネイティブ メモリのブロックを参照するスモール オブジェクト ヒープ内の 24 バイトのオブジェクトです。正しい?
(3a) このようなネイティブ メモリは、圧縮できないという点でラージ オブジェクト ヒープに似ていると想定しています...大きなオブジェクトがネイティブ メモリに配置されると、決して移動されないため、ネイティブ メモリの断片化は多くの問題を引き起こす可能性があります。ラージ オブジェクト ヒープの断片化。真実?または、基礎となるビットマップ/メタファイル データのより効率的な特別な処理はありますか?
(3b) したがって、別々に管理される 4 つの独立したメモリ ブロックが存在するようであり、それぞれが不足すると、同じメモリ不足例外が発生する可能性があります。オブジェクト ヒープ (GC によって収集されたが圧縮されていない 85KB を超えるマネージド オブジェクト)、ネイティブ メモリ (アンマネージド オブジェクト、おそらく圧縮されていない)、デスクトップ ヒープ (ウィンドウ ハンドルなどの限られたリソースが管理される場所)。これらの 4 つを適切に文書化しましたか? 他に知っておくべきことはありますか?
上記について誰でも提供できる明確さは大歓迎です。以上のことを詳しく説明している本や記事があれば教えてください。(私は必要な読書を喜んで行いますが、大部分の本はそれほど深く理解していないため、私がまだ知らないことは何も教えてくれません。)
ありがとう!