18

特に 64 ビットで malloc() が失敗する理由は何ですか?

私の特定の問題は、64ビットシステムで10GBの巨大なRAMチャンクをmallocしようとすることです。マシンには 12 GB の RAM と 32 GB のスワップがあります。はい、malloc は極端ですが、なぜそれが問題になるのでしょうか? これは、Intel コンパイラと MSFT コンパイラの両方を使用する Windows XP64 にあります。malloc は成功する場合もあれば、失敗する場合もあり、約 50% です。8GB の malloc は常に機能し、20GB の malloc は常に失敗します。malloc が失敗した場合、プロセスを終了して新しいプロセスを再度開始しない限り、繰り返されるリクエストは機能しません (その後、50% の成功が得られます)。他の大きなアプリは実行されていません。新たに再起動した直後でも発生します。

リクエストに割り当てるのに十分な大きさのアドレス範囲がないように、利用可能な 32 (または 31) ビットのアドレス空間を使い果たした場合、malloc が 32 ビットで失敗することを想像できます。

物理 RAMとハード ドライブのスワップ スペースを使い果たした場合、malloc が失敗することも想像できます。これは私には当てはまりません。

しかし、他の理由で malloc が失敗する可能性があるのはなぜでしょうか? 他の理由は思いつきません。

私は、特定の例よりも一般的な malloc の質問に興味があります。いずれにせよ、メモリ マップされたファイルに置き換える可能性があります。失敗した malloc() は、何よりもパズルのようなものです...ツールを理解し、基本に驚かないことを望んでいます。

4

9 に答える 9

6

VirtualAlloc()and をVirtualFree()直接使用してみましたか?これは、問題の切り分けに役立つ場合があります。

  • C ランタイム ヒープと NT ヒープをバイパスします。
  • 仮想アドレス空間を予約してからコミットできます。これにより、どの操作が失敗したかがわかります。

仮想アドレス空間の予約が失敗した場合 (あなたが言ったことから判断すると、そうすべきではありませんが)、Sysinternals VMMapが理由を説明するのに役立つ場合があります。「空き領域を表示」をオンにして、空き仮想アドレス空間がどのように断片化されているかを確認します。

于 2009-05-07T17:39:13.387 に答える
1

問題は、64 ビット アプリケーションをコンパイルするときに Visual Studio が WIN64 を定義しないことです。通常は WIN32 を保持しますが、これは 64 ビット アプリケーションでは正しくありません。_HEAP_MAXREQこれにより、が定義されたときにランタイムが 32 ビット値を使用するようになるため、大きな値はすべてmalloc()失敗します。プロジェクトを (プロジェクトのプロパティの下で、前処理された定義で) WIN64 に変更した場合、非常に大きなプロジェクトでmalloc()もまったく問題はありません。

于 2013-04-24T04:54:28.877 に答える
0

しかし、なぜ他にmallocが失敗する可能性があるのでしょうか。他の理由は思いつかない

以前に何度か暗黙のうちに述べたように、メモリの断片化のため

于 2009-05-07T10:56:15.257 に答える
0

断片化の可能性が高いです。簡単にするために、例を使用しましょう。

メモリは、単一の 12kb モジュールで構成されています。このメモリは、MMU で 1kb ブロックに編成されます。したがって、12 x 1kb ブロックがあります。OS は 100 バイトを使用しますが、これは基本的にページ テーブルを管理するコードです。したがって、交換することはできません。次に、すべてのアプリがそれぞれ 100 バイトを使用します。

OS とアプリケーション (200 バイト) だけを実行すると、既に 200 バイトのメモリ (2kb ブロックを占有) を使用していることになります。に利用できる正確に 10kb を残しますmalloc()

ここでmalloc()、2 つのバッファー (A (900 バイト)、B (200 バイト)) から始めました。次に、A を解放します。これで、9.8kb の空き領域ができました (不連続)。では、malloc()C (9kb) にしてみます。突然、あなたは失敗します。

テール エンドで 8.9k 連続し、フロント エンドで 0.9k 連続しています。B は最初の 1k ブロックと 2 番目の 1k ブロックにまたがるため、最初のブロックを最後に再マップすることはできません。

malloc()単一の 8kb ブロックを引き続き使用できます。

確かに、この例は少し不自然ですが、役に立てば幸いです。

于 2009-05-07T14:01:38.307 に答える
0

興味深い質問を見つけたので、理論的なPOVから調査してみました。

64 ビット (実際にはチップの制限により 48 ビットが使用可能であり、OS の制限によりそれ以下 (44 ビット?)) では、仮想メモリの断片化 (連続した仮想アドレス空間の欠如) によって制限されるべきではありません。その理由は、非常に多くの仮想アドレス空間があり、それを使い果たすのは実際的ではないからです。

また、仮想メモリは、割り当て要求を満たすために連続した物理メモリ アドレス範囲が存在する必要がないことを意味するため、物理メモリの断片化は問題にならないと予想できます。代わりに、十分に大きなメモリ ページのセットがあれば満足できます。

つまり、仮想メモリに適用される他の制限があります

Windows に確実に存在するもう 1 つの制限は、コミット制限です。これに関する詳細情報:

http://blogs.technet.com/b/markrussinovich/archive/2008/11/17/3155406.aspx

他の可能な制限が存在する可能性があります。たとえば、実際の実装が実際のハードウェアでどのように動作する必要があるかについての癖です。仮想アドレス空間から物理アドレス空間へのマッピングを作成しようとしたときに、仮想アドレス マッピングを行うためのページ テーブル内のエントリが不足していると想像してください... OS メモリ アロケータ コードは、このありそうもないシナリオを処理することを気にしますか? おそらくそうではありません...

仮想アドレス変換を行うためにページ テーブルが実際にどのように機能するかについての詳細は、こちらを参照してください。

http://en.wikipedia.org/wiki/Memory_management_unit

于 2015-03-20T23:49:25.347 に答える