メンテナンスを任されたイベント駆動型アプリがあります。約 100 のイベントが 30 秒ごとに別のタイマーで実行されます。時間の経過とともに、イベントは 1 秒あたり約 1 ~ 3 イベントの一定のストリームにエイリアスされます。メモリ使用量は、特定の 1 秒間に発生するイベントの数に依存しているわけではありません。各イベントは Web サービスからデータをポーリングし、LINQ2SQL DataContext を使用して以前にポーリングされたデータに対してデータをチェックし (完了時に DataContext を破棄または null アウトしません)、データが異なる場合は、データベースを更新し、新しいデータを次のようにプッシュします。 TCP 経由の受信者サービスへの XML メッセージ。
このアプリにはメモリ リークがあるようです。
- 30m 以上の実行 (デバッグまたはリリース) 後にのみマニフェストします。
- プロファイリング時にマニフェストしません [私は .NET Memory Profiler 4.5 を使用しています]
特徴: 起動時に、プログラムは ~30MB を使用します。時間が経つにつれて、このタスク マネージャーのメモリ使用量は、最初は 50 ~ 150 MB の間でわずかに低下し始め、最終的には悪化し、200 MB ~ 1 GB 以上の間で振動します。これが発生すると、1 ~ 2 秒の間に数回発生し、次の 10 ~ 20 秒ほどで 150MB 程度に落ち着きます。
私は、メモリ プロファイリングを使用して、この動作を実際にキャッチしようとしています。これまでのところ、私は成功していません。プロファイラーが監視していないときのように、アプリをメモリ使用量でポゴまたは振動させることはできません。ただし、ガベージ コレクターのステージ 1 および 2 の実行時に、メモリ使用量に方形波のようなパターンがあることに気付きました。 800MB+ (200MB から 1GB+) ではなく、10MB 幅。現在、Google Images によると、適切に機能するアプリのガベージ コレクションは、正方形というよりはノコギリ波のように見えます。
率直に言って、私のアプリが 1 秒以内に 200MB から 1GB+ のメモリ使用量を使用し、CPU を 100% に急上昇させない方法は見当たりません。
ガベージ コレクションとイベント処理の間で発生する可能性があるいくつかの問題について読んだことがありますが、調査できるパスがいくつかあり、どのパスに時間を費やすかを絞り込もうとしています。私はまだ .NET がかなり遅く、C を実行している組み込みデバイスに対して持っている「直感」を開発していません。これは、最初に調査する必要があるものをフィルター処理するのに役立ちます。イベント ハンドラーが [膨大な量のデータ] への参照を失ったり、再び取得したりしているような気がする場合はどうでしょう (これがどのように起こるかはわかりません)。ガベージ コレクタが実行され、メモリ使用量が 200MB に戻ります。
このアプリの以前のバージョンには、これらの問題はありませんでした。それ以来、私が行った2つの変更は次のとおりです
- 独自のデータ マネージャー (ハードコードされた SQL ステートメントを実行するために使用した ADORecordSetHelper オブジェクトを持っていた) の代わりに LINQ2SQL を利用する
- TCP XML メッセージを受信者に送信するために使用するソフトウェアの一部を変更します。#2で行っていることは単純であるため、それが問題の原因になる可能性がありますが、このメモリ使用量の動作は別のことを考えさせます.
この時点での私の主な質問は
- 作成したメソッドから戻る前に、LINQ2SQL DataContext で dispose を呼び出す必要がありますか?
- 代わりにそれらを無効にする必要がありますか?
- DataContext の作成後にメソッドのどこかで例外が発生した場合、DataContext が無期限にメモリに保持される可能性がありますか?
- LINQ クエリの結果を値型 (つまり、var ではなく int) に格納する場合、その結果は遅延ロードされますか、それとも変数が使用されると遅延ロードされますか?
- イベント駆動型フレームワークが仮想的に参照を失ったり取り戻したりする可能性はどのくらいありますか?
編集: イベントには、ここで説明したようなインスタンス ベースのサブスクリプションがあり、アプリの存続期間中、サブスクライブが解除されることはありません。
edit2: 最終的にプロファイラーでそれをキャッチすることができました。200MB の system.string が何らかの形で作成されているようです。GC の動作を除外してくれてありがとう。