13

私は現在、大量のメモリを必要とする医用画像処理のプロジェクトに取り組んでいます。ヒープの断片化を回避し、すでにメモリにロードされている画像データへのアクセスを高速化するためにできることはありますか?

アプリケーションはC++で記述されており、WindowsXPで実行されます。

編集:アプリケーションは、再フォーマット、ルックアップテーブルの計算、目的のサブ画像の抽出など、画像データを使用して前処理を行います...アプリケーションは処理中に約2 GBのRAMを必要とし、そのうち約1.5GBを使用できます。画像データ用。

4

9 に答える 9

17

医療画像処理を行っている場合は、一度に大きなブロックを割り当てている可能性があります(512x512、ピクセルあたり2バイトの画像)。画像バッファの割り当てのに小さなオブジェクトを割り当てると、断片化が発生します。

カスタムアロケータを作成することは、この特定のユースケースでは必ずしも難しいことではありません。Imageオブジェクトには標準のC++アロケータを使用できますが、ピクセルバッファには、Imageオブジェクト内ですべて管理されるカスタム割り当てを使用できます。簡単で汚い概要は次のとおりです。

  • 構造体の静的配列を使用します。各構造体には次のものがあります。
    • N個の画像を保持できるメモリの堅固なチャンク(チャンクは断片化の制御に役立ちます)最初のNを5程度にしてみてください
    • 対応する画像が使用されているかどうかを示すboolの並列配列
  • 割り当てるには、配列で空のバッファを検索し、そのフラグを設定します
    • 何も見つからない場合は、配列の最後に新しい構造体を追加します
  • 割り当てを解除するには、配列内の対応するバッファを見つけて、ブールフラグをクリアします

これは、バリエーションの余地がたくさんある単純なアイデアの1つにすぎません。主なトリックは、画像のピクセルバッファの解放と再割り当てを回避することです。

于 2008-09-29T21:35:17.533 に答える
5

答えはありますが、問題の詳細を知らずに一般化することは困難です。

32 ビットの Windows XP を想定しています。

数百 MB の連続したメモリを必要としないようにしてください。運が悪いと、いくつかのランダムな dll が使用可能なアドレス空間を介して不便なポイントにロードされ、連続したメモリの非常に大きな領域が急速に削減されます。必要な API によっては、これを防ぐのが非常に難しい場合があります。「通常の」メモリ使用量に加えて 2 つの 400MB ブロックのメモリを割り当てるだけで、最終的な「小さな」40MB ブロックを割り当てる場所がなくなることは、非常に驚​​くべきことです。

一方、適切なサイズのチャンクを一度に事前に割り当ててください。約 10MB 程度が適切な妥協点のブロック サイズです。データをこのようなサイズのチャンクに分割できれば、アドレス空間を合理的に効率的に埋めることができます。

それでもアドレス空間が不足する場合は、何らかのキャッシュ アルゴリズムに基づいてブロックをページ インおよびページ アウトできる必要があります。ページアウトする適切なブロックの選択は、処理アルゴリズムに大きく依存し、慎重な分析が必要になります。

ページアウトする場所を選択することは、別の決定です。それらを一時ファイルに書き込むだけにすることもできます。Microsoft の Address Windowing Extensions API を調査することもできます。どちらの場合でも、ページアウトされようとしている何かを指しているポインターをクリーンアップするようにアプリケーションの設計に注意する必要があります。そうしないと、本当に悪いことが起こります。

幸運を!

于 2008-09-29T21:43:32.380 に答える
5

大きな画像マトリックスに対して操作を実行する場合は、「タイリング」と呼ばれる手法を検討することをお勧めします。一般に、イメージをメモリにロードして、同じ連続するバイト ブロックが 1 行にピクセルを含まず、2D 空間の正方形を含むようにするという考え方です。この背後にある理論的根拠は、1 つのスキャン ラインではなく、2D で互いに近い操作をより多く実行することです。

これによってメモリ使用量が減ることはありませんが、ページのスワッピングとパフォーマンスに大きな影響を与える可能性があります。

于 2008-09-29T21:48:26.020 に答える
2

ここでヒットするのは、仮想アドレス範囲の制限です。これは、32bWindowsでは最大2GBになります。DirectXやOpenGLなどのグラフィカルAPIを使用すると、フレームバッファー、テクスチャ、および同様のデータに2GBの大部分が使用されることにも注意してください。

32bアプリケーションの1.5〜2 GBを実現するのは、非常に困難です。これを行う最もエレガントな方法は、64bOSと64bアプリケーションを使用することです。64b OSおよび32bアプリケーションでも、を使用している限り、これはある程度実行可能である可能性がありますLARGE_ADDRESS_AWARE

ただし、画像データを保存する必要があるため、ファイルマッピングをメモリストアとして使用することでこれを回避できる場合もあります。これは、メモリをコミットしてアクセスできるようにする方法で実行できますが、仮想を使用することはできません。まったくアドレス。

于 2008-11-05T08:38:19.037 に答える
2

問題に関する詳細情報 (言語など) がなくても、できることの 1 つは、割り当て、操作、および解放を行わずに、割り当てを再利用して割り当てチャーンを回避することです。dlmallocなどのアロケータは、Win32 ヒープよりも断片化を適切に処理します。

于 2008-09-29T21:28:49.950 に答える
1

手動のメモリ管理を実装する必要がある場合があります。画像データの寿命は長いですか?そうでない場合は、Apache Web サーバーで使用されるパターンを使用できます。つまり、大量のメモリを割り当てて、それらをメモリ プールにラップします。これらのプールを関数の最後の引数として渡すと、一時メモリを割り当てる必要性を満たすためにプールを使用できます。呼び出しチェーンが終了すると、プール内のすべてのメモリを使用できなくなるため、メモリ領域をスクラブして再度使用できます。割り当ては、ポインタに値を追加することだけを意味するため、高速です。非常に大きなメモリ ブロックを一度に解放するため、割り当て解除は非常に高速です。

アプリケーションがマルチスレッド化されている場合、クロススレッド通信のオーバーヘッドを回避するために、プールをスレッド ローカル ストレージに格納することが必要になる場合があります。

于 2008-09-29T21:31:10.287 に答える
1

ここで、断片化を回避し、最適化を回避しないことを意味していると推測します。また、管理されていない言語 (おそらく c または C++) を使用していると推測します。大きなメモリ チャンクを割り当ててから、割り当てられたメモリ ブロックからヒープ割り当てを提供することをお勧めします。このメモリ プールには大きなメモリ ブロックが含まれているため、断片化が起こりにくくなっています。要約すると、カスタム メモリ アロケータを実装する必要があります。

これに関するいくつかの一般的な考え方をここで参照してください。

于 2008-09-29T21:29:33.757 に答える
1

管理されたプラットフォームではシステム(ガベージコレクター)が断片化を処理するため、管理されていないものを使用していると思います。

C/C++ の場合、デフォルト以外のアロケータを使用できます。(stackowerflow のアロケータに関するいくつかのスレッドがすでにありました)。

また、独自のデータ ストレージを作成することもできます。たとえば、私が現在取り組んでいるプロジェクトでは、ビットマップ用のカスタム ストレージ (プール) があります (大量の連続したメモリの塊に格納します)。断片化が大きすぎる場合は、断片化して最適化します。

于 2008-09-29T21:30:38.557 に答える
0

大きなブロックを割り当てる可能性のある場所を正確に分離できる場合は、(Windowsでは)メモリマネージャーを経由せずにVirtualAllocを直接呼び出すことができます。これにより、通常のメモリマネージャ内での断片化が回避されます。

これは簡単な解決策であり、カスタムメモリマネージャーを使用する必要はありません。

于 2010-02-16T22:01:17.420 に答える