2012-01-23 1 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 на самом деле не такой большой ... больше как 32 Кбайт данных ...

+0

Вы можете отправить реальный код? Я не вижу, откуда в этом коде появляется pFullPathFile. – Joe

ответ

7

Исключение переполнения стека может происходить в любое время, когда стек превышает его максимальный размер. Обычно это делается с помощью ...

  • Имея глубоко вложенный стек, который не является рекурсивным. Подумайте о бурях событий, когда событие A ведет к событию B, которое приводит к событию C, в котором есть обработчики, которые глубоко увеличивают стек.
  • Имея неглубокую стек, который происходит после того, как несколько больших распределений стека
4

переполнение стека просто означает, что вы исчерпали стек, он не должен быть вызван рекурсии. Конечно, поскольку рекурсия использует стек, это часто является причиной исключения переполнения стека, но это не обязательно.

Это означает, что с предоставленной вами информацией не должно быть ничего, что может привести к переполнению стека в коде, который вы предоставили.

Темы в C# по умолчанию имеют стек 1 МБ, но вы можете create a new thread with a smaller stack. Вы сами создаете темы в этой программе и устанавливаете размер стека?

Кроме того, ознакомьтесь с разделом внешнего кода (щелкните правой кнопкой мыши, где он говорит «Внешний код» в окне «Стек вызовов», выберите «Показать внешний код»). Посмотрите, что-то выглядит неправильно, является ли какая-то каркас какой-то причиной, проходящей через множество вызовов методов для сохранения?

+0

У ASP.NET разные значения по умолчанию. –

0

В некоторых языках/времени выполнения переполнение стека может происходит из-за больших распределений памяти, которые не связаны с самим стеком вызовов. Вполне возможно, что «внешний код» (я предполагаю, что структура) работает либо в этой ситуации, либо на самом деле представляет собой проблему переполнения классического рекурсии, которую вы не видите, потому что вы не можете отлаживать ее.

2

Существует действительно рекурсивный вызов.

pDoc.Save() звонки WriteTo(XmlWriter w) на документ, который вызывает WriteContentTo(XmlWriter w).

Затем он вызывает WriteTo(XmlWriter w) на всех узлах корневого уровня, который будет содержать один элемент узла (возможно, также некоторые комментарии, пробелы, инструкции по обработке, декларацию документа ...).

На этом элементе, это заставит его написать свой тег («<», имя элемента, а затем все атрибуты), а затем с помощью вызова WriteContentTo(XmlWriter w) который вызывает WriteTo(XmlWriter w) на каждом дочернем элементе, который вызывает WriteContentTo(XmlWriter w), и так далее, и так на.

Следовательно, это действительно рекурсивно в том, как каждый элемент вызывает один и тот же метод для своих дочерних элементов и с достаточно глубоким документом на достаточно небольшом пространстве стека (по умолчанию для большинства приложений используется 1 МБ, но 256 КБ на ASP.NET), вы У меня будет переполнение стека.

Для записи вы также можете иметь переполнение стека без рекурсии, если вы так или иначе прогоняете пространство стека. stackalloc - отличный способ найти себя, делая только несколько звонков.

Если вы попали в беду из-за этой рекурсии, то помните, что реализация WriteTo по существу (вручную встраивание WriteContentTo в него):

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(); 
} 

Заменить это с итеративной версии, и вы выиграли» t переполняет стек. Конечно, если вам удалось каким-то образом привести документ в состояние, когда у него есть элемент, который является предком для себя (защищает ли XmlDocument от этого? Я не знаю, с моей точки зрения), тогда он превратится переполнение стека в бесконечный цикл, который, если что-то хуже.

Смежные вопросы