HtmlAgilityPack 库 StackOverflowException 解决方案

     最近试用HtmlAgilityPack 来解析html,试用过程中程序会抛出StackOverflowException异常,从MSDN上可以看到,从 .NET Framework 2.0 版开始,将无法通过 try-catch 块捕获 StackOverflowException 对象,并且默认情况下将终止相应的进程。

    调查原因,发现,当一个html结构非常复杂时,HtmlAgilityPack 的递归次数会非常多,于是就报StackOverflowException异常,google了一下,找到下面的解决方案

首先,在库中新增一个类:

	
public class StackChecker
{
    public unsafe static bool HasSufficientStack(long bytes)
    {
        var stackInfo = new MEMORY_BASIC_INFORMATION();
 
        // We subtract one page for our request. VirtualQuery rounds UP to the next page.
        // Unfortunately, the stack grows down. If we're on the first page (last page in the
        // VirtualAlloc), we'll be moved to the next page, which is off the stack! Note this
        // doesn't work right for IA64 due to bigger pages.
        IntPtr currentAddr = new IntPtr((uint)&stackInfo - 4096);
 
        // Query for the current stack allocation information.
        VirtualQuery(currentAddr, ref stackInfo, sizeof(MEMORY_BASIC_INFORMATION));
 
        // If the current address minus the base (remember: the stack grows downward in the
        // address space) is greater than the number of bytes requested plus the reserved
        // space at the end, the request has succeeded.
        return ((uint)currentAddr.ToInt64() - stackInfo.AllocationBase) >
            (bytes + STACK_RESERVED_SPACE);
    }
 
    // We are conservative here. We assume that the platform needs a whole 16 pages to
    // respond to stack overflow (using an x86/x64 page-size, not IA64). That's 64KB,
    // which means that for very small stacks (e.g. 128KB) we'll fail a lot of stack checks
    // incorrectly.
    private const long STACK_RESERVED_SPACE = 4096 * 16;
 
    [DllImport("kernel32.dll")]
    private static extern int VirtualQuery(
        IntPtr lpAddress,
        ref MEMORY_BASIC_INFORMATION lpBuffer,
        int dwLength);
 
    private struct MEMORY_BASIC_INFORMATION
    {
        internal uint BaseAddress;
        internal uint AllocationBase;
        internal uint AllocationProtect;
        internal uint RegionSize;
        internal uint State;
        internal uint Protect;
        internal uint Type;
    }
}

然后,在递归次数较多的地方(such as HtmlNode.WriteTo(TextWriter outText) andHtmlNode.WriteTo(XmlWriter writer)):)添加下面的代码:

if (!StackChecker.HasSufficientStack(4*1024))
                throw new Exception("The document is too complex to parse");

OK,大功告成!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏分布式系统进阶

一个有限状态机的C++实现

我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invi...

1404
来自专栏非著名程序员

Retrofit OKHttp 教你怎么持久化管理Cookie

? 投稿作者:黄海杰 原文链接: http://blog.csdn.net/lyhhj/article/details/51345386 绪论 最近小编有点...

35510
来自专栏菩提树下的杨过

Silverlight之ListBox/Style学习笔记--ListBox版的图片轮换广告

ListBox是一个很有用的控件,其功能直逼Asp.Net中的Repeater,它能实现自定义数据项模板,纵向/横向排列Item(如果扩展一下实现自行折行,几乎...

2135
来自专栏Flutter入门

Weex是如何在Android客户端上跑起来的

Weex可以通过自己设计的DSL,书写.we文件或者.vue文件来开发界面,整个页面书写分成了3段,template、style、script,借鉴了成熟的MV...

1874
来自专栏Seebug漏洞平台

抓住“新代码”的影子 —— 基于GoAhead系列网络摄像头多个漏洞分析

PDF 版本下载:抓住“新代码”的影子 —— 基于GoAhead系列网络摄像头多个漏洞分析

79210
来自专栏葡萄城控件技术团队

从Component对象到CodeDom——舞动你的Code系列(1)

我们经常会有这样的需求或者想法:动态的生成或者修改代码。当然,我们可以把代码看成字符串而直接修改,但是这种做法也未免太生硬了,能解决的问题有限;而另一个方式就是...

2079
来自专栏菩提树下的杨过

silverlight:对象拖动的优雅解决方案

对象拖动是一个老生常谈的话题,在SL上要实现对象拖动,一般有三种思路: 一、基于Canvas绝对定位布局的拖动 这种处理方法最简单,修改对象的Canvas.To...

19210
来自专栏菩提树下的杨过

asp.net与asp的session共享 及 asp的请求拦截

asp.net 与 asp 的session是无法直接共享的(底层的处理dll也不一样),要想互通session,只能用变通的办法: 一、asp.net -> ...

1887
来自专栏狐狸

状态模式(State)

模式的组成 环境类(Context): 定义客户感兴趣的接口。维护一个ConcreteState子类的实例,这个实例定义当前状态。 抽象状态类(State...

572
来自专栏后端之路

jsp改造之sitemesh注意事项

背景 现在各种现代化的浏览器确实惯坏了开发者 智能纠错 无论是忘记关闭标签甚至重复等等都有可能被chrome这些浏览器智能纠错===》chrome会合并多个bo...

2454

扫码关注云+社区