web-dev-qa-db-ja.com

32ビットWindows実行可能ファイルに/ LARGEADDRESSAWAREを使用することの欠点は?

実行可能ファイルの1つは大量のメモリを使用するため、このフラグにリンクする必要があります。
しかし、なぜ1つのEXEファイルに特別な扱いをするのですか。/LARGEADDRESSAWAREで標準化してみませんか?

したがって、問題は、/ LARGEADDRESSAWAREを必要としない場合でも、使用することに何か問題がありますか。すべてのEXEファイルの標準として使用してみませんか?

33
Arve

盲目的にLargeAddressAwareフラグを32ビット実行可能ファイルに適用すると、時限爆弾が展開されます!

このフラグを設定することにより、あなたはOSに証言しています:

はい、私のアプリケーション(および実行時にロードされるすべてのDLL)は最大4GBのメモリアドレスを処理できます。
したがって、プロセスのVASを2 GBに制限せずに、全範囲(4 GB)のロックを解除します。 "。

しかし、あなたは本当に保証できますか?
プロセスが使用する可能性のあるすべてのシステムDLL、Microsoft再配布可能ファイル、およびサードパーティモジュールに対して責任を負いますか?

通常、メモリ割り当ては仮想アドレスを下位から上位の順に返します。したがって、プロセスが大量のメモリを消費しない限り(または、仮想アドレス空間が非常に断片化されていない限り)、2GBの境界を超えるアドレスを使用することはありません。これは、上位アドレスに関連するバグを隠しています。

そのようなバグが存在する場合、それらを特定することは困難です。それらは散発的に「遅かれ早かれ」現れるでしょう。それは時間の問題です。

幸いなことに、Windows OSには非常に便利なシステム全体のスイッチが組み込まれています:
テストの目的で、MEM_TOP_DOWNレジストリ設定を使用します。
これにより、すべてのメモリ割り当てが通常のボトムアップではなく、トップダウンで実行されます。

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management]
"AllocationPreference"=dword:00100000

(これは16進数の0x100000です。もちろんWindowsを再起動する必要があります)

このスイッチを有効にすると、問題を「後で」ではなく「早く」特定できます。理想的には、「最初から」それらを見ることができます。

補足:最初の分析では、ツールVMmapSysInternals )を強くお勧めします。

結論:

32ビット実行可能ファイルにLAAフラグを適用する場合、TopDown AllocationPreferenceスイッチが設定されたx64OSで完全にテストする必要があります。

独自のコードの問題については、修正できる可能性があります。
非常に明白な例を1つ挙げると、メモリポインタに符号付き整数の代わりに符号なし整数を使用します。

サードパーティモジュールで問題が発生した場合は、作成者にバグの修正を依頼する必要があります。これを行わない限り、実行可能ファイルからLargeAddressAwareフラグを削除することをお勧めします。


テストに関する注意:

memTopDownレジストリスイッチは、それ自体がである「テストランナー」によって実行されるユニットテストに対して望ましい結果を達成していません。 notLAAが有効になっています。
参照: x86 LargeAddressAware互換性の単体テスト


PS:
また、非常に「関連性があり」、非常に興味深いのは、32ビットコードから64ビットへの移行です。
例については、以下を参照してください。

46
Opmet

多くのレガシーコードは、「負の」ポインタが無効であることを期待して記述されているためです。 32ビットプロセスの上位2Gbにあるものには、msbが設定されています。

そのため、Microsoftが安全にプレイするのははるかに簡単であり、(a)完全な4Gbを必要とし、(b)大容量メモリのシナリオで開発およびテストされたアプリケーションでフラグを設定する必要があります。

お気づきのように、それほど難しいことではありません。

Raymond Chen-彼のブログ The Old New Thing -は、すべての(32ビット)アプリケーションでオンにすることに関する問題をカバーしています。

11
Chris Becke

いいえ、このコンテキスト(C/C++)の「レガシーコード」は、ポインターのMSBで醜いトリックを実行するコードだけではありません。

また、正しい型を使用する代わりに、「int」を使用して2つのポインタの差、つまりメモリ領域の長さを格納するすべてのコードが含まれています。「size_t」:「int」は31ビットであり、処理できません。 2Gbを超える値。

コードの大部分を修正する方法は、コードを調べて、それらのすべて無害「符号付きと符号なしの混合」警告を修正することです。少なくとも、int型の引数が実際にはメモリ長である関数を定義していない場合は、ジョブの大部分を実行する必要があります。

ただし、その「レガシーコード」は、何も修正しなくても、おそらく明らかにかなり長い間正しく機能します。

1つのブロックに2Gb以上を割り当てる場合にのみ、中断します。または、互いに2Gb以上離れている2つの無関係なポインターを比較する場合。
関連のないポインターの比較は技術的には未定義の動作であるため、それを実行するコードはそれほど多くありません(ただし、確信は持てません)。
そして、合計で2Gb以上が必要な場合でも、実際には、プログラムがそれよりも大きい単一の割り当てを行うことはありません。実際、Windowsでは、LARGEADDRESSAWAREを使用しても、メモリの編成方法を考えると、デフォルトではそれほど多くを割り当てることはできません。 2Gbを超える連続ブロックを取得するには、システムをシャッフルする必要がありますDLL

しかし、マーフィーの法則によれば、この種のコードはwillある日壊れます。チェックせずにLARGEADDRESSAWAREを有効にした後、これが行われたことを誰も覚えていない場合は、非常に長い時間発生します。

6
jmd