5

大量の MSMQ キュー (現時点では約 10000) から読み取るアプリケーションがあります。queue.BeginPeekUInt32.MaxValue タイムアウトを使用して、キューからメッセージを受信します。メッセージがキューに表示されたら、それを処理してqueue.BeginPeek再度呼び出します。そのため、すべてのキューをリッスンしますが、メッセージ処理はスレッド プールで行われます。

メモリ使用量がゆっくりと増加していることに気付きました (2 週間の作業で 200 MB から 800 MB に増加します)。ダンプ ファイルを調べたところ、多くのフリー オブジェクトが含まれる典型的なヒープ フラグメンテーションの図が表示されます (サイズが数メガバイトのものもあります)。そして、穴の間にピンで留められたオブジェクトがあります。

これは、固定されたオブジェクトを作成するアンマネージ コードの呼び出しを操作する場合によくある状況のようです。しかし、私はインターネットで解決策を見つけられませんでした。

では、.NET のメモリ管理は非常に純粋なため、そのような単純なシナリオでさえ完了できないのでしょうか。

編集:サンプルアプリケーションでいくつかの調査を行いました。固定されたオブジェクト間のホール (フリー メモリ ゾーン、いわゆるフリー オブジェクト) は、新しいオブジェクトにメモリを割り当てるときに GC によって再利用されます。しかし、私の実稼働アプリケーションでは、固定されたオブジェクトは長生きし、最終的にそれらの間に穴が開いた第 2 世代で表示されます (GC は世代を分離する境界を移動するため)。通常の寿命の長いオブジェクトがほとんどないため、第 2 世代のダンプ ファイルにこの穴が見られます。

そのため、アプリケーションのメモリ消費量は 10000* (穴の平均サイズ) まで増加する可能性があります。(10000 は、将来的に増加する可能性のあるキューの数です)。現時点では、これを修正する方法がわかりません。唯一の方法は、時々アプリケーションを再起動することです。

繰り返しになりますが、なぜ .NET にはピン留めされたオブジェクト用の個別のヒープがないのでしょうか? (たぶんこれは初心者の質問です)。現時点では、アンマネージ コードで動作する非同期操作を呼び出すと、メモリの問題が発生する可能性があることがわかります。

4

2 に答える 2

4

MSMQ のマネージ ラッパーのソース コードを確認したところ、API を使用して本物の問題に遭遇したようです。呼び出しBeginPeekにより、アンマネージ API に渡される前に固定されるプロパティのコレクションが作成されます。メッセージが受信された場合にのみ、これらのプロパティの固定が解除されますが、メッセージの受信を継続するにはBeginPeek、この時点で呼び出す必要があり、時間の経過とともにメモリの断片化が発生します。

この断片化が本当に懸念される場合、私が思いつく唯一のハックは 1 時間ごとです。そのため、 へのすべての呼び出しをキャンセルしBeginPeek、ガベージ コレクションを強制してから、通常のリッスン操作を再開する必要があります。これにより、ガベージ コレクターが断片化を処理できるようになります。

于 2012-10-05T12:01:25.397 に答える
1

ピン留めされたオブジェクトが長寿命であることに問題がある場合、簡単な回避策はBeginPeek、短い期間でタイムアウトを使用して、それらが次世代に移動しないようにすることです。各タイムアウトの後EndPeekBeginPeek. マーティンが参照したプロパティが作成および破棄されるタイミングによっては、キュー オブジェクトを再作成する必要がある場合があります (明らかにキュー自体ではなく、管理されたラッパーだけです)。運が良ければ、そこまでする必要はありません。

于 2012-10-05T12:25:41.243 に答える