RAM集中型C#プロセスが数時間後に遅くなる

c# html-agility-pack memory-management multithreading performance

質問

私は、HTMLページを継続的に解析する責任を負うサーバー上でC#プロセス(サービス)を実行します。それはHTMLAgilityPackに依存します。症状は、時間の経過とともに遅くなり、遅くなるという症状です。

プロセスを開始すると、nページ/秒を処理します。数時間後、速度は約n / 2ページ/ sに低下します。それは数日後にn / 10に下がることができます。この現象は何度も観察され、かなり決定的である。プロセスが再起動されるたびに、正常に戻ります。

非常に重要なことは、私は同じプロセスで他の計算を実行することができ、速度が落ちることはないということです。プロセス自体は遅くはありません。 HTML解析のみが遅くなります。

私は最小限のコードでそれを再現することができました(実際に元のサービスの動作はもう少し極端ですが、このコードは動作を再現します)。

public static void Main(string[] args) {
    string url = "https://en.wikipedia.org/wiki/History_of_Texas_A%26M_University";
    string html = new HtmlWeb().Load(url).DocumentNode.OuterHtml;
    while (true) {
        //Processing
        Stopwatch sw = new Stopwatch();
        sw.Start();
        Parallel.For(0, 10000, i => new HtmlDocument().LoadHtml(html));
        sw.Stop();
        //Logging
        using(var writer = File.AppendText("c:\\parsing.log")) {
            string text = DateTime.Now.ToString() + ";" + (int) sw.Elapsed.TotalSeconds;
            writer.WriteLine(text);
            Console.WriteLine(text);
        }
    }
}

この最小コードでは、プロセスが開始されてから経過した時間数の関数として速度(ページ/秒)が表示されます。

ここに画像の説明を入力

明白な原因はすべて除外されています:

  • HTMLページがより大きくても異なってもかまいません(最小限のコードでは同じページです)
  • フルRAM:プロセスは32 GBで約500 MBを使用します
  • 他のプロセスはCPUまたはRAMを使用する

それはRAMとメモリ割り当てに関するものかもしれません。私は、HTMLAgilityPackが小さなオブジェクトのメモリ割り当て(HTMLノードと文字列)をたくさん作成することを知っています。メモリ割り当てとマルチスレッドがうまく連携していないことは明らかです。しかし、私はプロセスがどのように遅く、遅くなることが理解できません。

RAMを集中的に(多くの割り当てを)処理するのが遅くなり、遅くなる可能性があるCLRまたはWindowsについて何か知っていますか?たとえば、ある方法でメモリ割り当てを行っているスレッドにペナルティをかけるようなことはありますか?

受け入れられた回答

私はHTMLAgilityPackを使用して同様の動作に気付きました。

私は、ある歩留まりのデータがスペースリークを開始すると、コンパイラのローカル変数が問題を引き起こし始めるクラスを生成することを発見しました。コードはありません... bla bla、ここに私のFirst Aidキット

  1. 適切な戦略を立てて app.config内のGCコレクションの状態を変更すると断片化に役立ちます。
  2. あなたがそれらを必要としなくなるとすぐにあなたが必要としないときにnullを返すようにしてください。IEnumerablesがメソッドの呼び出しメソッドとスコープで呼び出されてスコープがあなたのメモリをきれいにするのを待ってはいけません。あなたが思うより! ILSpyでコードを開き、 <> d__0(0)の生成クラスを見てください。 d __のように生成されたものが表示されます。X = X;この場合、Xはフラグメントまたはページ全体を保持することができます。
  3. あなたのローカル変数は、IEnumable反復ではアクセスできないので、ヒープには持ち込まれません。
  4. ロックが問題になり始めると、GCがブロックされてしまうような大量のアイテムが4世代のRAMに漂っています。 GCがガベージコレクションを実行できるようにスレッドを一時停止しています。
  5. HTMLAgilityの最悪の事は、それが本当の問題に終わる断片であるということです

    私はあなたがあなたのHTML断片の範囲を検討し始めるとき、あなたはものがうまく始めることに気付くでしょう。 SOSWinDbgを使って実行を見て、あなたの記憶をダンプして見てください。

どうやってするか。

  1. WinDebugを開き、F6を押してプロセスにアタッチします(フィールドにプロセスIDを入力してOKを押します)
  2. 入力してmemeoryに実行をロードします

    .loadby sos clr

  3. 入力してください

    !dumpheap -stat

アプリケーションで割り当てられたメモリ項目をメモリアドレスとサイズでグループ化し、低ヘッダから高ヘッダにソートすると、System.String []のようなものが表示されます。あなたが最初に調査したいと思っている症状。

今すぐ誰が入力できるかを確認する

!dumpheap -mt <heap address>

そして、そのメモリテーブル(MT)を使用しているアドレスとそれが使用するRAMのサイズが表示されます。

今あなたが入力するyodeのx100行を通過するのではなく、面白​​くなる

!dumpheap -mt <heap address>

それが印刷されるのは、メモリを割り当てたファイルと行です。コンパイラはクラスを生成し、悲しみとそれが保持するバイトを引き起こします。

これは「プロダクションデバッグ」と呼ぶことができ、サーバーにアクセスできれば動作します。

助けになったと願って、

ウォルター




ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ