【问题标题】:Work-around a StackOverflowException解决 StackOverflowException
【发布时间】:2022-01-18 08:31:39
【问题描述】:

我正在使用 HtmlAgilityPack 解析大约 200,000 个 HTML 文档。

我无法预测这些文档的内容,但是一个这样的文档会导致我的应用程序失败并返回 StackOverflowException。该文档包含以下 HTML:

<ol>
    <li><li><li><li><li><li>...
</ol>

大约有 10,000 个 &lt;li&gt; 元素像这样嵌套。由于 HtmlAgilityPack 解析 HTML 的方式,它会导致 StackOverflowException

很遗憾,在 .NET 2.0 及更高版本中无法捕获 StackOverflowException。

我确实想知道为线程的堆栈设置更大的大小,但是设置更大的堆栈大小是一种技巧:它会导致我的程序使用更多的内存(我的程序启动了大约 50 个线程来处理 HTML,所以所有这些线程的堆栈大小会增加),如果再次遇到类似情况,则需要手动调整。

还有其他我可以采用的解决方法吗?

【问题讨论】:

  • 并非如此。除非您想切换到不同的库,否则我认为没有比增加堆栈大小更好的方法了。也许有一种方法可以仅为需要它的线程设置堆栈大小?

标签: html-agility-pack stack-overflow


【解决方案1】:

我刚刚修补了一个我认为与您描述的相同的错误。已将补丁上传到 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 并显示消息“文档有多个嵌套标签。这可能是由于页面没有正确关闭标签。”

我是如何使用 Hap After Patch...

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

【讨论】:

    【解决方案2】:

    理想情况下,长期解决方案是修补 HtmlAgilityPack 以使用堆堆栈而不是调用堆栈,但这对我来说是一项太大的任务。我暂时丢失了我的 CodePlex 帐户详细信息,但当我找回它们时,我将提交有关该问题的问题报告。我还注意到,此问题可能会给任何使用 HtmlAgilityPack 清理用户提交的 HTML 的站点带来拒绝服务攻击漏洞 - 精心制作的过度嵌套的 HTML 文档会导致 w3wp.exe 进程终止。

    同时,我认为最好的方法是手动覆盖最大线程堆栈大小。我之前的说法是错误的,即更大的堆栈大小意味着所有线程都会自动消耗该内存(似乎内存页面是在线程堆栈增长时分配给它的,而不是一次性分配的)。

    我复制了&lt;ol&gt;&lt;li&gt; 页面并进行了一些实验。我发现当堆栈大小小于 2^21 字节 (2MB) 时,我的程序失败,但最大大小为 2^22 字节 (4MB) 成功 - 并且我书中的 4MB 作为“可接受”传递" hack...暂时。

    【讨论】:

      【解决方案3】:

      这应该可行:

      
      HtmlDocument.MaxDepthLevel = 10000;
      var doc = new HtmlDocument();
      try
      {
          doc.LoadHtml(document);
      }
      catch(Exception ex)
      {
          Console.WriteLine("Exception while loading html: " + ex);
          yield break;
      }
      
      

      【讨论】:

      • 您的答案可以通过添加有关代码的作用以及它如何帮助 OP 的更多信息来改进。
      • 自 2.0 CLR 以来,您无法捕获 StackOverflowException
      猜你喜欢
      • 1970-01-01
      • 2019-01-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-25
      • 2016-12-16
      • 2011-04-27
      相关资源
      最近更新 更多