49

メモリ割り当ての失敗により、(Windows Server 2003 で実行されている) 長時間実行されるサーバー プロセスが例外をスローするという問題が発生することがあります。私たちは、メモリの断片化が原因でこれらの割り当てが失敗しているのではないかと考えています。

したがって、私たちは私たちに役立ついくつかの代替メモリ割り当てメカニズムを検討しており、誰かが私に最善のものを教えてくれることを願っています:

1) Windowsの低断片化ヒープを使用する

2) jemalloc - Firefox 3で使用されている

3) Doug Lea のmalloc

私たちのサーバー プロセスはクロスプラットフォームの C++ コードを使用して開発されているため、どのソリューションもクロスプラットフォームであることが理想的です (*nix オペレーティング システムはこの種のメモリの断片化に悩まされますか?)。

また、LFH が Windows Server 2008 / Vista の既定のメモリ割り当てメカニズムになっているという考えは正しいですか?... お客様がサーバー OS をアップグレードするだけで、現在の問題は「解消」されますか?

4

10 に答える 10

38

まず、リソース リークを提案した他の投稿者に同意します。あなたは本当に最初にそれを除外したい.

願わくば、現在使用しているヒープ マネージャーに、ヒープ内で使用可能な実際の合計空き領域 (すべての空きブロックにわたって) と、分割されているブロックの合計数をダンプする方法があります。空きブロックの平均サイズが、ヒープ内の合計空き領域と比較して比較的小さい場合は、断片化の問題があります。または、最大の空きブロックのサイズをダンプして、それを合計の空き領域と比較すると、同じ結果が得られます。断片化が発生している場合、最大の空きブロックは、すべてのブロックで使用可能な空き領域の合計に比べて小さくなります。

上記について明確にするために、すべての場合において、ヒープ内の割り当てられたブロックではなく、ヒープ内の空きブロックについて話しています。いずれにせよ、上記の条件が満たされない場合は、何らかのリーク状況が発生しています。

したがって、リークを除外したら、より優れたアロケーターの使用を検討できます。質問で提案されているDoug Lea の mallocは、一般的な用途のアプリケーションに非常に優れたアロケーターであり、ほとんどの場合非常に堅牢です。別の言い方をすれば、ほとんどのアプリケーションで非常にうまく機能することが実証されています。ただし、すべてのアプリケーションに最適なアルゴリズムはありません。管理アルゴリズムのアプローチは、その設計に対する適切な病理学的条件によって破られる可能性があります。

断片化の問題が発生するのはなぜですか? - 断片化の問題の原因は、アプリケーションの動作によって引き起こされ、同じメモリ アリーナ内で大きく異なる割り当ての有効期間に関係しています。つまり、一部のオブジェクトは定期的に割り当てられて解放されますが、他のタイプのオブジェクトはすべて同じヒープ内で長期間存続します... 寿命の長いオブジェクトは、アリーナのより広い領域に穴を開け、それによって攻撃を防ぐものと考えてください。解放された隣接ブロックの合体。

この種の問題に対処するためにできる最善の方法は、ヒープを論理的にライフタイムが類似したサブアリーナに分割することです。実際には、一時的なヒープと永続的なヒープ、または似たようなライフタイムのものをグループ化するヒープが必要です。

問題を解決する別の方法として、割り当てサイズをより類似または同一にする方法を提案している人もいますが、内部フラグメンテーションと呼ばれる別のタイプのフラグメンテーションが作成されるため、これはあまり理想的ではありません。必要以上のメモリをブロックに割り当てることによって。

さらに、Doug Lea のような優れたヒープ アロケーターでは、ブロック サイズをより似たものにする必要はありません。これは、アロケーターが既に 2 のべき乗サイズのバケット スキームを実行しているため、malloc( ) - 実際には、彼のヒープ マネージャーは、アプリケーションが調整できるよりもはるかに堅牢に自動的にそれを行います。

于 2008-09-14T02:12:23.013 に答える
15

誤ってメモリリークを早期に除外したと思います。わずかなメモリリークでも、深刻なメモリフラグメンテーションを引き起こす可能性があります。

アプリケーションが次のように動作すると仮定します
。10MBを割り当てます
1バイトを割り当てます10MBを
解放します
(おっと、1バイトを解放しませんでしたが、1バイトを気にします)

これは非常に小さなリークのようです。割り当てられたメモリサイズの合計だけを監視する場合、ほとんど気付かないでしょう。ただし、このリークにより、最終的にアプリケーションメモリは次のようになります


無料–10MB


[割り当てられた-1バイト]


無料–10MB


[割り当てられた-1バイト]


無料–10MB


このリークは気付かれません...11MBを割り当てるまで
ミニダンプにフルメモリ情報が含まれていると仮定すると、DebugDiagを使用してリークの可能性を見つけることをお勧めします。生成されたメモリレポートで、割り当てカウント(サイズではなく)を注意深く調べます。

于 2008-10-12T10:46:16.837 に答える
5

あなたが示唆するように、Doug Lea の malloc はうまくいくかもしれません。これはクロスプラットフォームであり、出荷コードで使用されています。少なくとも、テストのためにコードに簡単に統合できる必要があります。

固定メモリ環境で何年も働いてきたので、固定されていない環境であっても、この状況は確かに問題です。CRT アロケーターは、パフォーマンス (速度、無駄なスペースの効率など) の面でかなり悪い傾向があることがわかりました。長期間にわたって優れたメモリ アロケータが必要な場合は、独自のメモリ アロケータを作成する必要があると確信しています (または、dlmalloc のようなものが機能するかどうかを確認してください)。秘訣は、割り当てパターンで動作するものを作成することです。これは、他のほとんどのことと同様に、メモリ管理の効率と関係があります。

dlmalloc を試してみてください。私は間違いなくそれを高く評価します。かなり調整可能であるため、コンパイル時のオプションの一部を変更することで、より効率的になる可能性があります。

正直なところ、新しい OS の実装で「なくなる」ことに依存するべきではありません。N 年後にサービス パック、パッチ、または別の新しい OS が問題を悪化させる可能性があります。繰り返しになりますが、堅牢なメモリ マネージャーを必要とするアプリケーションでは、コンパイラで利用可能なストック バージョンを使用しないでください。あなたの状況に合ったものを見つけてください。dlmalloc から始めて調整し、状況に最適な動作が得られるかどうかを確認します。

于 2008-09-14T02:21:08.530 に答える
2

割り当て解除の量を減らすことで、断片化を減らすことができます。

たとえば、サーバー側のスクリプトを実行している Web サーバーの場合、ページを出力するための文字列を作成することがあります。すべてのページ要求に対してこれらの文字列を割り当てて割り当てを解除する代わりに、それらのプールを維持するだけで、さらに必要なときにのみ割り当てますが、割り当てを解除しないでください (しばらくすると、もう割り当てない状況になることを意味します。足りる)

_CrtDumpMemoryLeaks(); を使用できます。デバッグ ビルドの実行時にメモリ リークをデバッグ ウィンドウにダンプすることはできますが、これは Visual C コンパイラに固有のものだと思います。(crtdbg.h にあります)

于 2008-09-13T21:21:56.783 に答える
1

断片化を疑う前に、リークを疑うでしょう。

メモリ集約型のデータ構造については、再利用可能なストレージ プール メカニズムに切り替えることができます。ヒープではなくスタックにより多くのものを割り当てることもできるかもしれませんが、実際には大きな違いはないと思います。

valgrind のようなツールを起動するか、集中的なログ記録を行って、解放されていないリソースを探します。

于 2008-09-13T21:10:38.230 に答える
1

@nsaners - 問題はメモリの断片化にあると確信しています。大容量 (5 ~ 10 MB) のメモリ チャンクが割り当てられている場合の問題を指摘するミニダンプを分析しました。また、プロセス (オンサイトおよび開発中) を監視してメモリ リークをチェックしましたが、何も検出されませんでした (メモリ フットプリントは一般的に非常に低いです)。

于 2008-09-13T21:28:44.363 に答える
1

この問題は Unix でも発生しますが、通常はそれほど悪くはありません。

Low-framgmentation ヒープは私たちを助けてくれましたが、私の同僚はスマート ヒープに誓って います (これは何年もの間、私たちの製品のいくつかでクロス プラットフォームで使用されてきました)。残念ながら、他の事情により、今回は Smart Heap を使用できませんでした。

また、ブロック/チャンクの割り当てと、スコープに精通したプール/戦略、つまり、ここでは長期的なもの、あちらではリクエスト全体、あちらでは短期的なものなどを検討しています。

于 2008-09-13T21:59:32.060 に答える
1

いつものように、通常はメモリを浪費して速度を上げることができます。

この手法は、汎用アロケーターには役に立ちませんが、その場所はあります。

基本的に、アイデアは、すべての割り当てが同じサイズであるプールからメモリを返すアロケータを作成することです。どのブロックも他のブロックと同様に優れているため、このプールが断片化することはありません。異なるサイズのチャンクで複数のプールを作成し、要求された量よりまだ大きい最小のチャンク サイズのプールを選択することで、メモリの浪費を減らすことができます。このアイデアを使用して、O(1) で実行されるアロケーターを作成しました。

于 2008-09-13T22:55:00.333 に答える
-1

シンプルで手っ取り早い解決策は、アプリケーションを複数のプロセスに分割することです。プロセスを作成するたびに、新しい HEAP を取得する必要があります。

メモリと速度は少し (スワッピング) 低下する可能性がありますが、高速なハードウェアと大容量の RAM が役立つはずです。

これは、スレッドがまだ存在していなかったときに、デーモンを使用した古い UNIX のトリックでした。

于 2018-11-03T17:40:21.817 に答える