2011-11-17 1 views
8

私のアプリケーションは、作業を実行するために大量のメモリと大きなデータ構造を必要とします。 多くの場合、アプリケーションには1 GB以上のメモリが必要です。場合によっては、数ギガバイトのメモリがあるため、アプリケーションの64ビット版を実際に使用する必要があります。メモリに最小限の断片化が生じるように、WindowsにDLLをロードするように強制します。

以前は、メモリが1.6〜1.7 GBのメモリ使用量に達した場合、「メモリ不足」または「メモリ不足」の状況に近いことをユーザに簡単に説明できました。メモリを減らしたり、64ビット版に移行することができます。

昨年私は、アプリケーションがすでにメモリ不足になる前に約1GBしか使用しないことに気付きました。いくつかの調査の後、この問題の原因はメモリ断片化であるように見えました。私はアプリケーションのメモリ使用量を見るためにVMMAP(SysInternalsユーティリティ)を使いました。このようなものを見ました: Address Space Fragmentation

オレンジ色の領域は私のアプリケーションによって割り当てられたメモリです。紫色の部分は実行可能なコードです。

イメージの下半分に表示されているように、紫色の領域(DLL)は多くの異なるアドレスに読み込まれ、メモリが断片化する原因となります。私の顧客が多くのデータを持っていない場合は問題にはなりませんが、顧客が1 GBを超えるデータセットを持ち、アプリケーションの一部に大きなブロック(50 MBなど)が必要な場合は、メモリ割り当てに失敗し、アプリケーションがクラッシュする可能性があります。

ほとんどのデータ構造はSTLベースであり、多くの場合連続したメモリを必要としませんが、場合によっては(非常に大きな文字列など)、連続したメモリブロックが必要です。残念ながら、そのような連続したメモリブロックを必要としないようにコードを変更することは必ずしも可能ではありません。

質問は以下のとおりです。

  • どのように私は、DLLのは、明示的に顧客のコンピュータ上のすべてのDLLの上REBASEを使用せずに、または明示的にすべてのDLLのをロードすることなく、メモリにロードされている場所に影響を与えることができます。
  • 独自のアプリケーションマニフェストファイルにDLLのロードアドレスを指定する方法はありますか?
  • また、Windowsに(マニフェストファイル経由で)DLLを分散させないように指示する方法があります(この散乱はASLRと呼ばれています)。

もちろん、私がアプリケーションのマニフェストファイル内で影響を与えることができる解決策は、WindowsのDLLの自動/動的ロードに依存しているからです。

私のアプリケーションは、混合モード(管理対象+非管理)アプリケーションですが、アプリケーションの大部分は管理対象外です。

誰か提案がありますか?

+0

これはあなたを助けるかもしれませんか? http://msdn.microsoft.com/en-us/library/f7f5138s.aspx – detunized

+1

mmm、本当に同時に大量のメモリが必要ですか? Process Monitorはログを仮想メモリに保存し、必要に応じてプロセスのメモリアドレス空間にデータを持ち込むだけです。http://blogs.msdn.com/b/oldnewthing/archive/2004/08/10/211890.aspxでコードを確認してください例 –

+1

答えを残している皆さんがASLRの成果を理解しているかどうかはわかりません:http://en.wikipedia.org/wiki/ASLR –

答えて

5

最初に、仮想アドレス空間の断片化が必ずしもメモリ不足の状態を引き起こしてはいけません。これは、アプリケーションが適切なサイズの連続したメモリブロックを個割り当てなければならない場合に当てはまります。さもなければ、断片化の影響は軽微でなければならない。

ほとんどのデータは「STLベース」と言われていますが、たとえば巨大なstd::vectorを割り当てると、連続したメモリブロックが必要になります。

AFAIKロード時にDLLの優先マッピングアドレスを指定する方法はありません。そのため、2つのオプションしかありません:DLLファイルを再構築するか、自分自身でDLLを実装するか(これは些細なことではありません)。

通常、標準のWindows API DLLをリベースする必要はなく、アドレス空間に非常に緊密にロードされます。一部のサードパーティのDLL(Windowsフック、ウイルス対策のインジェクションなど)から断片化が届く可能性があります。

3

マニフェストではできません。リンカの/ BASEオプションで行う必要があります。 Linker + Advanced + IDEのベースアドレス。最も柔軟な方法は、/ BASE:@ filename、キー構文を使用して、リンカーがテキストファイルからベースアドレスを読み取るようにすることです。

テキストファイルを埋め込む最も良い方法は、[デバッグ+ Windows +モジュール]ウィンドウからです。デバッガにロードされたプログラムのリリースビルドを取得し、シバン全体をロードします。 Debug + Break Allを選択してウィンドウを開き、コピーしてテキストファイルに貼り付けます。必要な書式と一致するように編集し、アドレス列からロードアドレスを計算します。 DLL間に十分なスペースを残して、テキストファイルを常に調整する必要はありません。

+0

もちろん、これは一般的なシステムで見つかったすべてのフックDLL 。グラフィックドライバ。アンチウイルス。マウスドライバ。 etc –

+0

えええええええええええええええええええええええええええええええええええええええとボルトは、rebase.exeツールでハッキングすることができます。あなたがあなたの製品を出荷する予定がない限り、これを行うことをお勧めします。 –

1

問題のライブラリがロードされる前に独自のコードを実行することができれば、あらかじめ割り当てようとする大きなアドレス空間を確保することができます。

それ以外の場合は、原因となるDLLを特定して、DLLがロードされている理由を特定する必要があります。たとえば、.NET、言語のランタイムライブラリ、独自のコード、または使用しているサードパーティ製ライブラリの一部ですか?

あなたのコードで最も賢明な解決策は、おそらく動的リンクの代わりに静的を使用することです。これは言語ランタイムでも可能であり、サードパーティのライブラリでも可能です。

第三者のライブラリでは、暗黙的な読み込みから明示的な読み込みに変更することができるため、読み込みはアドレス空間のチャンクを予約した後にのみ行われます。

.NETライブラリについて何かできることがあるかどうかわかりません。あなたのコードのほとんどは管理されていないので、.NETを取り除くために管理対象コンポーネントを削除することは可能かもしれません。あるいは、.NETの部分を別のプロセスに分割することもできます。

+0

...大規模な連続メモリブロックの必要性を排除するために、必要に応じてプログラムをリファクタリングする方がはるかに賢明でしょう。 –

関連する問題