2012-01-23 7 views
4

私はそれがこのようになります... stackoverflowのを生成することができるとは思われないコードのセグメントのスタックオーバーフロー例外を取得しています:再帰的な理由でスタックオーバーフローが発生することはありますか?

public String WriteToFile(XmlDocument pDoc, String pPath) 
{ 
    string source = ""; 
    string seq = ""; 
    string sourcenet = ""; 

    XmlNodelist sourceNode = pDoc.GetElementsByTagName(XmlUtils.Nodes.Source); 
    source = sourceNode.Item(0).InnerText; 

    XmlNodelist sqList= pDoc.GetElementsByTagName(XmlUtils.Nodes.Seq); 
    seq = sqList.Item(0).InnerText; 

    XmlNodelist sourceNets = pDoc.GetElementsByTagName(XmlUtils.Nodes.SourceNets); 
    sourcenet = sourceNets.Item(0).InnerText; 

    string fileName = Folders.GetMyFileName(source, seq, sourcenet); 
    string fullPath = Path.Combine(pPath, fileName); 

    pDoc.Save(pFullPathFile); <--- Stackoverflow is raised here 

    return pFullPathFile; 
} 

あなたも何ら再帰呼び出しは、まだありません"外部コード"に行く前に深さが2のコールスタックを調べてください(私はそれは外部ではなく、スレッドを開始するフレームワークの一部であり、デバッグはオフになっていると推測しています)。

¿再帰呼び出し以外の理由で例外が発生する可能性はありますか?それは常にpDoc.Saveメソッド呼び出しで失敗します...そして、pDocは実際にはそれほど大きくはありません...もっと32KBのデータのように...

+0

実際のコードを投稿できますか?私はこのコードでpFullPathFileがどこから来るのか分かりません。 – Joe

答えて

7

スタックのオーバーフローの例外は、スタックがそれを超えるといつでも発生することがあります最大サイズ。これはほとんどの場合、一般的に次のように行われます。

  • 再帰的ではない深くネストされたスタックを持つ。イベントAがイベントBにつながるイベントストームを考えると、イベントCはすべてスタックを深く成長させるハンドラを持っています。
4

スタックオーバーフローは、単にあなたがスタックを使い果たしたことを意味し、いくつかの大規模なスタック割り当てた後に発生する浅いスタックを持って、それが再帰によって引き起こされる必要はありません。もちろん、再帰はスタックを利用するため、スタックオーバーフロー例外の原因となることがよくありますが、必ずしもそうである必要はありません。

あなたが提供した情報では、提供したコードにスタックオーバーフローの原因となるものはないと言われています。

デフォルトでC#のスレッドには1MBのスタックがありますが、create a new thread with a smaller stackにすることができます。このプログラムで自分でスレッドを作成していて、スタックサイズを設定していますか?

また、外部コードセクションを見てください(コールスタックウィンドウの外部コードを右クリックし、「外部コードを表示」を選択してください)。何かが間違っているかどうかを確認し、何らかの理由でフレームワークが保存を行うためのメソッド呼び出しを多数行っていますか?

+0

ASP.NETのデフォルト値が異なります。 –

0

一部の言語/ランタイムでスタックオーバーフローが発生するは、コールスタック自体とは関係のない大きなメモリ割り当てのために発生します。 「外部コード」(私はフレームワークと仮定します)がその状況に陥っているか、実際にはデバッグできないため、実際には古典的な再帰オーバーフローの問題があります。

2

実際に再帰呼び出しがあります。

pDoc.Save()WriteContentTo(XmlWriter w)を呼び出すドキュメントのWriteTo(XmlWriter w)を呼び出します。

これはルートレベルのすべてのノードでWriteTo(XmlWriter w)を呼び出します。これは1つの要素ノード(場合によってはコメント、空白、処理命令、ドキュメント宣言など)を含みます。その要素で

、これには及びそうWriteContentTo(XmlWriter w)を呼び出して、すべての子要素、上WriteTo(XmlWriter w)を呼び出し、WriteContentTo(XmlWriter w)を呼び出して、その後、それはそのタグ(「<」、要素名、その後、任意の属性)を書き込みますに。

これは、各要素がその子要素に対して同じメソッドを呼び出し、充分に小さいスタック領域(デフォルトではほとんどのアプリケーションで1MB、ASP.NETでは256KB)で十分に深いドキュメントを使用する方法で再帰的ですスタックオーバーフローが発生します。レコードの

、あなたはまた、限り、あなたはあなたのスタック空間を一つの方法または別のを焼くよう再帰せずに、スタックオーバーフローを持つことができます。 stackallocは、数回の通話だけでこれを行うことができます。

あなたが原因この再帰に困っている場合は、(手動にWriteContentToをインライン化)WriteToの実装が本質的であることを覚えておいてください:

w.WriteStartElement(this.Prefix, this.LocalName, this.NamespaceURI); 
if (this.HasAttributes) 
{ 
    XmlAttributeCollection attributes = this.Attributes; 
    for (int i = 0; i < attributes.Count; i++) 
    { 
     attributes[i].WriteTo(w); 
    } 
} 
if (this.IsEmpty) 
{ 
    w.WriteEndElement(); 
} 
else 
{ 
    for (XmlNode node = this.FirstChild; node != null; node = node.NextSibling) 
    { 
    node.WriteTo(w); 
    } 
    w.WriteFullEndElement(); 
} 

「反復バージョンでこれを置き換え、そしてあなたが勝ちましたスタックをオーバーフローさせます。もちろん、もしあなたが何らかの形で文書をそれ自身の祖先である要素に持っていれば(XmlDocumentはそれを保護していますか?私は頭の上からわかりません)、それは無限ループへのスタックオーバーフロー。何かが悪い場合に。

関連する問題