5

ミニダンプによると、特定のファイルが再帰降下パーサーでスタック オーバーフローを引き起こしている状況に遭遇しました。残念ながら、問題を再現するためにこれを行うファイルの例を手に入れることができません (クライアントには機密性に関する懸念があります)。

明らかにパーサーには注意が必要ですが、今のところ私の最優先事項は、プログラムを実行し続けることです。その場しのぎの措置として、これがプログラム全体をダウンさせないようにするにはどうすればよいですか?

私の最初の選択は、オーバーフローが発生する前にパーサーを適切に中止できるように、スタックのスペースが不足していることを予測する方法を見つけることです。ファイルの解析に失敗することは、許容されるオプションです。2 番目の選択肢は、エラーを発生させ、エラーをキャッチしてログに記録し、残りのデータを続行することです。

解析はParallel.ForEach()ループで行われています。それが助けになるなら、私はそれを他のアプローチと交換したいと思っています。

編集: 本当にキラーになるのは、現在のスレッドのスタックのサイズとスタック ポインターの位置を取得できる場合です。これは可能ですか?

編集 2: 私は最終的に誰かからサンプル ファイルを絞り出し、デバッガーでエラーをトラップすることができました。それは私たちに属しているコードではないことが判明しました - 例外はHtmlAgilityPackのどこかで発生しています。そのため、まったく別のタックルを見つけようとする必要があるようです。

4

2 に答える 2

3

デスクトップ CLR では、スタックには既定で 1 MB の制限がありますが、増やすことができます。

継続渡しスタイルを使用して、スタックの代わりにヒープを使用できます。

C# 5.0 では、このプロセスを自動化するコンパイラによって提供される非同期メカニズムがあります。私は最新のビルドでこれを試していません。Alex が述べたように、C# では末尾呼び出しの最適化がサポートされていません。これは、問題の解析に F# を採用する十分な理由になる可能性があります。F# を使用した字句解析と解析に関する資料を次に示します。この記事 で説明されているように、YMMV 。

不正な入力が存在する場合でもプログラムを安定させるには、グラフ サイクルの検出も必要です。

より多くの情報を収集する方法として、コール スタックの深さを追跡するアキュムレータ整数をニードル スルーできます。これは、コールスタックによって消費されるメモリに直接変換されませんが、一般的なアイデアが得られます。たとえば、その数がユーザー設定可能または事前定義されたしきい値よりも大きい場合、独自の例外をスローしてキャッチできます。

public void Recursive(int acc)
{
    if (acc > myLimit)
       throw new MyOverflowException(acc); 

    Recursive(acc+1);
}

そして呼び出しサイトで:

try { Recursive(0); } catch (MyOverflowException) { /* handle it*/ }

リクエストに応じて、まさにこのトピックに関する Eric Lippert のすばらしいブログにリンクします。

于 2012-08-02T19:13:03.000 に答える
0

SOE が原因でスレッドがクラッシュすると、プロセス全体が停止し、それに対してできることはあまりありません。

回復手段として、代わりにパーサーを別のプロセスとして起動し、子プロセスと通信する IPC メカニズムをセットアップすることができます。そうすれば、メイン プロセスに影響を与えることなく、子プロセスを自由に終了させることができます。

于 2012-08-02T19:55:17.893 に答える