2009-10-19 6 views
8

私は何ヶ月も連続して動作するVC++ NTサービスを開発しています。 VC++ランタイムヒープを集中的に使用します。明らかに、ヒープの断片化は、ある時点で誤動作する可能性があります(メモリが不足していると考えている)。私のC++プログラムでヒープフラグメンテーションを検出して見積もる方法は?

ヒープフラグメンテーションが発生する可能性が高いと推定されるサービスについて、どのようなテストを実行できますか?

答えて

2

私は、このデータを提供する独自のメモリマネージャー(または購入者)を作成するのが最善の方法だと思います。それ以外の方法では、ヒープ自体が変更され、結果が無効になります。

実装が簡単な戦略は、サイズの異なるメモリブロックを割り当てて、障害を待つことです。しかし、それは良い方法だとは思いません。とにかく - ブロックサイズが大きいほど、それは失敗しませんでした、より少ない断片化。しかし、メモリマネージャによっては、ブロックを割り当てることで結果を変更することができます。


編集:統計を示すスラブアロケータ(コメント用のthx)に関するリンクが見つかりました。それはドイツ語ですが、記事の英語版にはそれほど多くの情報は含まれていません。翻訳にはbabelfishを使用してください。

http://de.wikipedia.org/wiki/Slab_allocatorbabelfish version

http://www.usenix.org/event/usenix01/full_papers/bonwick/bonwick.pdf

+0

+1スラブアロケータ。 – user7116

+0

しかし、メモリマネージャを置き換えるのは、そのメモリマネージャを本番環境で使用する場合を除いて、測定するだけです。よりよい解決策は、実際のメモリアロケータを計測し、その断片化を測定することです。これを行うには、alloc/free呼び出しをラップするか、メモリマネージャに使用可能なフックがあるかどうかを確認します。 –

0

私はトビアスに同意する - 独自のメモリ管理を行うことは、これを行うための優れた方法です。私はこの種のコードを書くと信じている少数の開発者しか知りません...

もう一つの可能​​性は、毎回あなたのオブジェクトにガベージコレクション/コンソリデーションを行うことです。つまり、あなたのサービスは、それが使用するメモリを「最適化」しながらしばらくの間は非アクティブになることがありますが、あなた自身のメモリ管理なしであなたが望む動作を保証できるかどうかは確かではありません。

5

ヒープフラグメンテーションの問題を防ぐ方法については、いくつかの回答がありましたが、どちらも本当に直接質問に対処していません。断片化の問題がどの程度発生する可能性が高いかを推定する唯一の方法は、多くの使用をシミュレートし、断片化を測定することです。

NTサービスなので、何ヶ月か使用をシミュレートするのは主に多くのリクエストを急いで行うことです。通常はリクエストを受け取るよりも速くリクエストを行うことができるため、通常はリクエストを受け取ることが期待されるレートに応じて、おそらく数時間のリクエストをわずか数時間でシミュレートできます。 )。

月の作業量をシミュレートしたら(またはそうしているときでも)、断片化の程度を確認するためにヒープを調べる必要があります。これは簡単ではありませんが、通常は可能です。まず、スレッドをサービスプロセスに注入します(「スレッドインジェクション」でグーグルにするか、その順序で何か情報が得られるはずです)。それから、ヒープを歩く必要があります。フリーであるブロックは(特に)ほとんどの要求を満たすことができないほど小さすぎます。 MS VC++を使用していると仮定すると、_heapwalkでヒープを歩くと、ヒープ内の各ブロックのアドレス、サイズ、およびステータス(フリーまたは使用中)をヒープに伝えます。

最後の詳細:これにより有意義な結果が得られるように、実行ファイルと挿入されたスレッドを含むDLLの両方をDLLのランタイムライブラリにリンクする必要があります。これは、プロセス全体に1つのヒープがあることを意味します。つまり、注入されたスレッドは、サービスで使用されているヒープを歩くことになります。標準ライブラリを静的にリンクすると、DLLとサービスはそれぞれ独自のヒープを持ちます。 DLLは独自のヒープを歩き、サービスプロセスで使用されているヒープについては何も教えてくれません。

0

私は確かにメモリのステータスを与えることができるウィンドウのためのツールがありますが、この問題を念頭に置いてサービスを開発する必要があります。

まず、あなたが実行する割り当てが何であるかを理解する必要があります。私はそれを行う簡単な方法は、新しい演算子と削除演算子をオーバーライドすることであると思うし、これらの新しい演算子から、あなたの割り当てのいくつかの統計をカウントして、あなたのコンパイラのデフォルトのnewとdelete演算子を呼び出す必要があります。

あなたが考えるべき最低限の統計は、共通のブロックサイズ範囲の割り当て数です。

15バイトの0バイトの ブロック、32バイト、16バイトのブロック、48バイト、32のバイトとの間のブロック、...

また、各ブロックのサイズ範囲

の逐次割当の番号を追加することができこのデータを収集した後は、ブロックサイズをに調整して、フラグメンテーションの問題を軽減することができます。

位置合わせのための最高の簡単な技術は、16で割る最も近い数値に数値を整列させるために、例えば2

のパワーであるブロックを使用することで、次の関数を使用することができ

int align(int size) 
{ 
    return ((size + 15) & ~0x0000000F); 
} 

もちろん、あなたの統計情報を使って、2のべき乗を選んで整列させるべきです。 ターゲットは、割り当てのほとんどが数ブロックの範囲に入り、同時にアライメントのオーバーヘッドを合理的に保つための数値に到達することです。

幸運... Windowsのための低断片化ヒープ上

1

Switchinは古いシステム上で仕事をして助けることができます。デフォルトに切り替え、新しいシステムの(Vistaでは、Server 2008の)

HANDLE heaps[1025]; 
    DWORD nheaps = GetProcessHeaps((sizeof(heaps)/sizeof(HANDLE)) - 1, heaps); 
    for (DWORD i = 0; i < nheaps; ++i) { 
    ULONG enableLFH = 2; 
    HeapSetInformation(heaps[i], HeapCompatibilityInformation, &enableLFH, sizeof(enableLFH)); 
    } 

上 は、Sysinternalsのメモリの断片化に関する優れた概要を示します(現在はマイクロソフト)からツールVMMapがあります。

1

断片化を検出する最も簡単な方法は、プログラムが実行する最大の割り当てを決定し、少なくとも2倍の量を割り当てることです。割り当てが失敗した場合、すなわち、NULLを返し、コードによって決定されるヒープの使用状況 - このような何かをWindowsの

PROCESS_MEMORY_COUNTERS counters; 
if(GetProcessMemoryInfo(process, &counters, sizeof(counters))){ 
    result = counters.WorkingSetSize; 
} 

には、通常75%が、あなたは間違いなく断片化の問題が発生しているシステムメモリの一部の割合よりも少ないです。

関連する問題