我的代码段似乎没有产生堆栈溢出的堆栈溢出异常......看起来像这样:
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 :(得分:7)
如果堆栈超出其最大大小,则可能发生堆栈溢出异常。这主要是通过......来完成的。
答案 1 :(得分:4)
堆栈溢出只是意味着你已经耗尽了堆栈,它不需要由递归引起。当然,因为递归利用堆栈,它通常是堆栈溢出异常的原因,但它不需要。
话虽如此,根据您提供的信息,听起来并不会导致您提供的代码中出现堆栈溢出。
默认情况下,C#中的线程有1MB堆栈,但您可以create a new thread with a smaller stack。你是否自己在这个程序中创建线程,并设置堆栈大小?
另外,查看外部代码部分(右键单击Call Stack窗口中的External Code,选择“Show external code”)。看看是否有什么东西看起来是错误的,框架是否由于某种原因经过大量的方法调用来进行保存?
答案 2 :(得分:2)
确实有一个递归的电话。
pDoc.Save()
在文档上调用WriteTo(XmlWriter w)
,调用WriteContentTo(XmlWriter w)
。
然后在根级别的所有节点上调用WriteTo(XmlWriter w)
,这将包含一个元素节点(可能还有一些注释,空格,处理指令,文档声明......)。
在该元素上,这将导致它写入其标记('&lt;',元素名称,然后是任何属性),然后调用WriteContentTo(XmlWriter w)
,在每个子元素上调用WriteTo(XmlWriter w)
,调用WriteContentTo(XmlWriter w)
,依此类推等等。
因此,对于每个元素如何在其子元素上调用相同的方法,并且在足够小的堆栈空间上使用足够深的文档(在大多数应用程序上默认为1MB,在ASP.NET上为256KB),这确实是递归的。会有堆栈溢出。
对于记录,只要以这种或那种方式烧毁堆栈空间,您也可以在没有递归的情况下进行堆栈溢出。 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();
}
将其替换为迭代版本,您不会溢出堆栈。当然,如果你以某种方式设法把文件放到一个条件,它有一个元素,它是一个自己的祖先(XmlDocument防止这个?我不知道我的头顶),然后它将转向堆栈溢出到无限循环中,如果有什么更糟的话。
答案 3 :(得分:0)
在某些语言/运行时,由于与调用堆栈本身无关的大内存分配,可能会发生堆栈溢出 。 “外部代码”(我假设框架)完全有可能在这种情况下运行,或者实际上有一个你看不到的经典递归溢出问题,因为你不一定要调试它。