何日も何ヶ月も再起動せずに実行するはずの Windows コンソール アプリがあります。アプリは、MSMQ から「作業」を取得して処理します。作業チャンクを同時に処理する 30 のスレッドがあります。
MSMQ からの各ワーク チャンクは約 200 KB で、そのほとんどは 1 つの String オブジェクトに割り当てられます。
これらの作業チャンクを約 3 ~ 4 千処理した後、アプリケーションのメモリ消費量が途方もなく高く、1 ~ 1.5 GB のメモリを消費していることに気付きました。
私はプロファイラーを介してアプリを実行し、このメモリのほとんど (おそらくギグ程度) が大きなオブジェクト ヒープで使用されていないことに気付きましたが、構造は断片化されています。
これらの未使用 (ガベージ コレクション) バイトの 90% が以前に割り当てられた文字列であることがわかりました。私は、MSMQ から入ってくる文字列が割り当てられ、使用され、割り当てが解除されたため、断片化の原因になっているのではないかと疑い始めました。
GC.Collect(2 または GC.Max...) のようなものは、大きなオブジェクト ヒープを gc しますが、圧縮しないため、役に立たないことを理解しています (これが問題です)。したがって、これらの文字列をキャッシュして何らかの方法で再利用する必要があると思いますが、文字列は不変であるため、StringBuilders を使用する必要があります。
私の質問は次のとおりです。基本的な構造を変更せず (つまり、MSMQ を使用してこれを変更することはできません)、LOH の断片化を避けるために毎回新しい文字列を初期化することを回避する方法はありますか?
ありがとう、ヤニス
更新: これらの「作業」チャンクが現在どのように取得されているかについて
現在、これらは MSMQ に WorkChunk オブジェクトとして格納されています。これらの各オブジェクトには、Contents という文字列と、Headers という別の文字列が含まれています。これらは実際のテキスト データです。必要に応じてストレージ構造を別のものに変更したり、必要に応じて基になるストレージ メカニズムを MSMQ 以外のものに変更したりできます。
ワーカーノード側では現在行っています
WorkChunk チャンク = _Queue.Receive();
したがって、この段階でキャッシュできるものはほとんどありません。どういうわけか構造を変更すれば、少し進歩できると思います。いずれにせよ、この問題を解決しなければならないので、何ヶ月もの作業を無駄にしないために必要なことは何でもします。
更新:以下の提案をいくつか試してみたところ、この問題はローカル マシン (Windows 7 x64 および 64 ビット アプリを実行) では再現できないことに気付きました。これは物事を非常に困難にします-誰かが理由を知っていれば、この問題をローカルで解決するのに本当に役立ちます.