1

プロセスが多くのリソグラフィ計算を行うため、mmap を使用してメモリ プールにメモリを割り当てました。プロセスに大量のメモリが必要な場合は、mmap を使用してチャンクを割り当て、使用後にメモリ プールに入れます。プロセスで同じチャンク メモリが再び必要な場合は、メモリを使用するのではなく、プールから直接取得します。再度マップします (必要なすべてのメモリを割り当てず、プロセスの開始時にプールに入れます)。mmaps 関数の間には、malloc() や new() など、mmap を使用しないメモリ malloc があります。

問題は次のとおりです。memset() を使用してすべてのチャンク データをメモリ プールに入れる前に 0 に設定すると、プロセスは次のように仮想メモリを使いすぎます。フォーマットは「mmap(size)=virtual address」です。

mmap(4198400)=0x2aaab4007000
mmap(4198400)=0x2aaab940c000
mmap(8392704)=0x2aaabd80f000
mmap(8392704)=0x2aaad6883000
mmap(67112960)=0x2aaad7084000
mmap(8392704)=0x2aaadb085000
mmap(2101248)=0x2aaadb886000
mmap(8392704)=0x2aaadba89000
mmap(67112960)=0x2aaadc28a000
mmap(2101248)=0x2aaae028b000
mmap(2101248)=0x2aaae0c8d000
mmap(2101248)=0x2aaae0e8e000
mmap(8392704)=0x2aaae108f000
mmap(8392704)=0x2aaae1890000
mmap(4198400)=0x2aaae2091000
mmap(4198400)=0x2aaae6494000
mmap(8392704)=0x2aaaea897000
mmap(8392704)=0x2aaaeb098000
mmap(2101248)=0x2aaaeb899000
mmap(8392704)=0x2aaaeba9a000
mmap(2101248)=0x2aaaeca9c000
mmap(8392704)=0x2aaaec29b000
mmap(8392704)=0x2aaaecc9d000
mmap(2101248)=0x2aaaed49e000
mmap(8392704)=0x2aaafd6a7000
mmap(2101248)=0x2aacc5f8c000

mmap の最後 - 最初 = 0x2aacc5f8c000 - 0x2aaab4007000 = 8.28G

しかし、メモリ プールに入れる前に memset を呼び出さないと、次のようになります。

mmap(4198400)=0x2aaab4007000
mmap(8392704)=0x2aaab940c000
mmap(8392704)=0x2aaad2480000
mmap(67112960)=0x2aaad2c81000
mmap(2101248)=0x2aaad6c82000
mmap(4198400)=0x2aaad6e83000
mmap(8392704)=0x2aaadb288000
mmap(8392704)=0x2aaadba89000
mmap(67112960)=0x2aaadc28a000
mmap(2101248)=0x2aaae0a8c000
mmap(2101248)=0x2aaae0c8d000
mmap(2101248)=0x2aaae0e8e000
mmap(8392704)=0x2aaae1890000
mmap(8392704)=0x2aaae108f000
mmap(4198400)=0x2aaae2091000
mmap(4198400)=0x2aaae6494000
mmap(8392704)=0x2aaaea897000
mmap(8392704)=0x2aaaeb098000
mmap(2101248)=0x2aaaeb899000
mmap(8392704)=0x2aaaeba9a000
mmap(2101248)=0x2aaaec29b000
mmap(8392704)=0x2aaaec49c000
mmap(8392704)=0x2aaaecc9d000
mmap(2101248)=0x2aaaed49e000

mmap 最後 - 最初 = 0x2aaaed49e000 - 0x2aaab4007000= 916M

したがって、最初のプロセスは「メモリ不足」になり、強制終了されます。

プロセスでは、mmap メモリ チャンクは完全には使用されないか、割り当てられていても使用されません。つまり、たとえば、キャリブレーションの前に、プロセス mmap 67112960(64M) は使用されません (このデータの書き込みまたは読み取りメモリ領域) または最初の 2M バイトだけを使用してから、メモリ プールに入れます。

mmapは仮想アドレスを返すだけで、物理メモリは遅延割り当てを使用することを知っています。これらのアドレスで読み取りまたは書き込みを行うと割り当てられます。

しかし、私を混乱させたのは、なぜ仮想アドレスがこれほど増加したのかということです。centos 5.3 を使用しました。カーネル バージョンは 2.6.18 です。libhoard と GLIBC(ptmalloc) の両方でこのプロセスを試しましたが、どちらも同じ動作でした。

以前に同じ問題に遭遇した人はいますか?考えられる根本的な原因は何ですか?

ありがとう。

4

1 に答える 1

1

VMA (仮想メモリ領域、AKA メモリ マッピング) は連続している必要はありません。最初の例では ~256 Mb、2 番目の例では ~246 Mb を使用しています。

一般的なmalloc()実装ではmmap()、大規模な割り当て (通常は 64Kb を超える) に対して自動的に を使用し、対応するチャンクをmunmap(). mmap()したがって、大規模な割り当てを手動で行う必要はありません。malloc()ライブラリがそれを処理します。

ing の場合mmap()、カーネルは特別なゼロ ページの COW コピーを返すため、書き込まれるまでメモリを割り当てません。ゼロ化により、メモリが実際に割り当てられます。アロケータに返して、必要なときに新しいメモリ チャンクを要求することをお勧めします。

結論: システムがニーズに対して不十分であることが証明されない限り、独自のメモリ管理を作成しないでください。実際の負荷でニーズに対して著しく優れていることが証明された場合にのみ、独自のメモリ管理を使用してください。

于 2013-09-01T12:47:53.890 に答える