You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Blazor Server中HTML Agility Pack引发内存持续升高问题排查

Blazor Server下HtmlAgility Pack内存泄漏问题解决思路

问题核心原因

Blazor Server的每个用户会话对应一个Circuit,组件实例、类级变量等会被Circuit上下文持有,只要Circuit未销毁(用户未断开连接),这些引用就会阻止GC回收对象。而控制台应用没有这种持久化的会话上下文,所以对象能正常被回收。你的代码里docs列表如果是类级变量,会一直持有所有HtmlDocument实例,直接导致内存无法释放。

具体解决方案

  1. 不要长期持有HtmlDocument实例
    爬取网页后,只提取你需要的数据(比如文本、属性值),不要把整个HtmlDocument存入列表。处理完数据后立即切断对它的引用,让GC能回收:

    // 定义一个仅存所需数据的类
    public class PageData
    {
        public string Title { get; set; }
        public string Content { get; set; }
    }
    
    List<Task<PageData>> throttledTasks = new List<Task<PageData>>();
    var web = new HtmlWeb();
    foreach (var link in bracketLinks)
    {
        throttledTasks.Add(Task.Run(async () =>
        {
            await ssThrottle.WaitAsync();
            try
            {
                using var doc = web.Load(link); // 新版HtmlDocument支持IDisposable,用using自动清理
                if (doc == null) return null;
    
                // 只提取需要的数据,不保存整个文档
                return new PageData
                {
                    Title = doc.DocumentNode.SelectSingleNode("//h1")?.InnerText.Trim(),
                    Content = doc.DocumentNode.SelectSingleNode("//div[@class='content']")?.InnerText.Trim()
                };
            }
            finally
            {
                ssThrottle.Release();
            }
        }));
    }
    
    // 处理结果,此时所有HtmlDocument已失去引用
    var allData = (await Task.WhenAll(throttledTasks)).Where(d => d != null).ToList();
    
  2. 避免类级变量持有大对象集合
    如果你的docs列表是组件类的成员变量,会被Circuit持续持有。把它改成局部变量,仅在爬取过程中使用,任务完成后自动失去引用。

  3. 将爬取逻辑移到独立服务
    把网页爬取逻辑封装到一个Scoped/Transient服务中,而不是直接放在组件里。服务的生命周期更可控,不会和组件实例绑定过紧,减少Circuit对爬取相关对象的引用。

  4. 手动清理HtmlDocument资源
    对于旧版不支持IDisposable的HtmlAgility Pack,处理完数据后手动清空节点,帮助GC回收:

    HtmlDocument doc = web.Load(link);
    try
    {
        // 提取数据
    }
    finally
    {
        doc.DocumentNode.RemoveAll(); // 清空所有节点
        doc = null; // 主动切断引用
    }
    
  5. 不要依赖手动GC.Collect()
    Blazor Server的GC时机由运行时管理,手动调用通常无效,重点还是切断不必要的引用。

内容的提问来源于stack exchange,提问作者jcordell

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 06:31:11