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

.NET 6应用内存占用过高:大字符串驻留问题排查求助

.NET 6应用高内存占用问题分析与解决

问题背景

生产环境运行的.NET 6应用出现异常高内存占用:仅4个System.String实例就占用了2GB内存。通过dotnet-dump工具分析得到以下关键信息:

dumpheap -stat 输出

7f6f4964f8f0 18,152 1,466,966,959 System.Byte[]
7f6f48fad2e0 51,915 1,981,308,612 System.String

gcroot 分析结果(部分)

对大字符串地址执行gcroot后,发现其通过以下链被持留:

7f65298bf530 7f6f4facc029 System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
        r15:
          -> 7f6547f46900     System.Threading.Thread+StartHelper
          -> 7f66486d8ab8     System.Threading.ExecutionContext
          -> 7f664863e128     System.Threading.AsyncLocalValueMap+MultiElementAsyncLocalValueMap
          -> ...
          -> 7f654811f9c8     System.Diagnostics.Activity
          -> ...
          -> 7f695b756528     System.String

大字符串内容(dc命令读取)

字符串为JSON格式,包含大量类元数据、自动生成的闭包类(如<>c__DisplayClassXX_0)、方法调用细节等冗余内容:

{"Target":{"handler":{"Target":{"<>4__this":{},"act":{"Transfer":null,"TraceId":">>>>>aaa-432-
","TransferId":"15","SeqNum":"08","TriggeredBy":2,"TriggeredAt":"2024-12-․19T12:30:08.9597687Z"},"transfer":null,"blacklisted":[56]},"Method":{"Name":"<Initiate>g__Handler|0","DeclaringType":"ServiceName.Infrastructure.modules.ServiceOutgoing.Actions.ServiceActionAction+
<>c__DisplayClass10_0, ServiceName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",...

已排查步骤:移除Sentry监控、移除所有日志组件,问题仍未解决;服务配置与其他微服务一致,未发现注册问题。


原因分析

  1. 大字符串的来源:字符串是包含闭包/委托的复杂对象序列化后的结果,其中自动生成的<>c__DisplayClass系列类携带了大量冗余的程序集元数据,导致单个字符串体积异常庞大。
  2. 内存泄漏的核心原因:大字符串被System.Diagnostics.Activity的标签列表持有,而Activity又被ExecutionContext中的AsyncLocal存储引用。由于线程池线程会复用ExecutionContext,Timer线程(从gcroot中可见TimerQueueTimer)会长期持有这些上下文,导致Activity及关联的大字符串无法被GC回收。
  3. 残留的AsyncLocal引用:即使移除了Sentry,之前的AsyncLocal上下文没有被正确清理,线程池线程复用这些上下文时,会持续持有大字符串的引用。

解决方案

  1. 定位并修复Activity标签的错误设置

    • 检查所有调用Activity.AddTag、Activity.SetTag的代码,禁止将复杂对象(如委托、闭包实例)直接序列化后放入标签,仅保留必要的简单值(如TraceId、TransferId等)。
    • 排查是否有第三方组件自动向Activity注入了冗余标签。
  2. 确保Activity被正确回收

    • 在请求处理完成或异步任务结束后,显式调用Activity.Current?.Dispose(),触发Activity的清理逻辑,避免其被AsyncLocal长期持有。
    • 若使用ASP.NET Core,确保请求结束时Activity的生命周期被正确管理(可通过中间件统一清理)。
  3. 清理AsyncLocal上下文

    • 检查是否有自定义的AsyncLocal存储,在使用完成后显式移除对应的值,避免上下文被线程池线程复用。
    • 对于Timer任务,在任务执行完成后,手动重置或清理关联的ExecutionContext。
  4. 升级.NET 6补丁

    • 升级到.NET 6的最新补丁版本,修复早期版本中Activity或AsyncLocal可能存在的内存泄漏bug。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 09:50:55