我正在使用HtmlAgilityPack解析大约200,000个HTML文档。
我无法预测这些文档的内容,但是一个这样的文档会导致我的应用程序失败并显示StackOverflowException
。该文档包含此HTML:
<ol>
<li><li><li><li><li><li>...
</ol>
大约有10,000个<li>
元素嵌套。由于HtmlAgilityPack解析HTML的方式导致StackOverflowException
。
不幸的是,在.NET 2.0及更高版本中无法捕获StackOverflowException。
我确实想知道为线程的堆栈设置更大的大小,但设置更大的堆栈大小是一个黑客:它会导致我的程序使用更多的内存(我的程序启动大约50个线程来处理HTML,所以所有这些线程的堆栈大小会增加)并且如果再遇到类似的情况则需要手动调整。
我可以采用其他解决方法吗?
答案 0 :(得分:5)
我刚刚修补了一个错误,我认为该错误与您的描述相同。将补丁上传到hap项目站点......
http://www.codeplex.com/site/users/view/sjdirect(参见2012年3月8日的补丁)
或者在此处查看有关问题和结果的更多文档....
https://code.google.com/p/abot/issues/detail?id=77
实际修复是...... 添加了HtmlDocument.OptionMaxNestedChildNodes,可以设置它们以防止由大量嵌套标记引起的StackOverflowExceptions。它将抛出一个ApplicationException,消息“Document包含多个X嵌套标记。这可能是因为页面没有正确关闭标记。”
我在修补程序后如何使用Hap ...
HtmlDocument hapDoc = new HtmlDocument();
hapDoc.OptionMaxNestedChildNodes = 5000;//This is what was added
string rawContent = GETTHECONTENTHERE
try
{
hapDoc.LoadHtml(RawContent);
}
catch (Exception e)
{
//Instead of a stackoverflow exception you should end up here now
hapDoc.LoadHtml("");
_logger.Error(e);
}
答案 1 :(得分:2)
理想情况下,长期解决方案是修补HtmlAgilityPack使用堆栈而不是调用堆栈,但这对我来说太大了。我暂时丢失了我的CodePlex帐户详细信息,但是当我收回它时,我会提交一份有关问题的问题报告。我还注意到,此问题可能会对使用HtmlAgilityPack清理用户提交的HTML的任何网站提出拒绝服务攻击漏洞 - 精心设计的过度嵌套的HTML文档会导致w3wp.exe进程死亡。
与此同时,我认为最好的方法是手动覆盖最大线程堆栈大小。我之前的陈述中错误的是,更大的堆栈大小意味着所有线程都会自动消耗该内存(似乎内存页面在增长时为线程堆栈分配,而不是一次性)。
我制作了<ol><li>
页面的副本并进行了一些实验。我发现我的程序在堆栈大小小于2^21
字节时失败,但最大大小为2^22
成功 - 这是4MB,在我的书中传递为“可接受的”黑客......现在。