V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
drymonfidelia
V2EX  ›  .NET

有没有 .NET 大神帮忙看看困扰了好几个大神一年的内存泄露问题,优化了一年越变越严重,现在一小时崩一次

  •  1
     
  •   drymonfidelia · 2024-09-26 17:00:02 +08:00 · 5553 次点击
    这是一个创建于 366 天前的主题,其中的信息可能已经有所发展或是发生改变。
    这一年在 V 站关于这个问题已经发了好几个贴了,一直没解决 /t/1037900
    已经从 ASP.NET Core 5 升级到 6 了,之前升过 8 内存泄露更严重了,又退回 6
    最早加每 5 分钟强制 GC 一次,缓解了几个月,又开始两天一崩
    然后搞了双实例负载均衡,两台机器 4 小时重启一次,重启时间错开,缓解了几个月
    最近请求量翻了两倍,然后变成了一小时一崩,这么频繁重启再接下去肯定会出现重启也解决不了问题的情况,只好再来求助
    目前请求量是每天 6~9 千万(客户端大量轮询请求,随硬件分发无法更新,导致请求量比较大)
    按照 https://learn.microsoft.com/zh-cn/dotnet/core/diagnostics/debug-memory-leak 的教程,运行 10 分钟后抓取 dump 的 heap statistics 如下
    https://pastebin.com/BnxB8S0R

    另外 analyze 的时候所有命令都提示 ERROR: The GC heap is not in a valid state for traversal. (Use -ignoreGCState to override.) 加上 -ignoreGCState 又不返回内容,不知道为什么,stackoverflow 上的几个方法都无效
    26 条回复    2024-10-31 16:24:32 +08:00
    Metatron7
        1
    Metatron7  
       2024-09-26 17:10:41 +08:00   ❤️ 3
    supemaomao
        2
    supemaomao  
       2024-09-26 17:31:15 +08:00
    给个建议,不知道适不适合 op ,如果你能在本机调试复现的话,用 JB 的 dotMemory (其它的当然也行) 跑一下,每隔 10 分钟拍一个快照,对比快照能知道是哪里的内存没被释放。如果是在服务器上的话,那我就没试过了。
    Bazingal
        3
    Bazingal  
       2024-09-26 17:37:50 +08:00
    大于 0.5MB 的对象加起来才 900M ,总共占用 7G 多,应该是大量小对象占用的
    sss15
        4
    sss15  
       2024-09-26 17:52:51 +08:00
    我也想到了这个人,但没想起名字,github 和博客园都私信找他看看吧,他的博文都是处理这种的
    0o0o0o0
        5
    0o0o0o0  
       2024-09-26 17:54:54 +08:00
    这个统计总和才 900 多 MB ,得把小于 0.5M 的,也就是所有的对象的统计输出都发出来才行
    luckybricks9711
        6
    luckybricks9711  
       2024-09-26 17:56:47 +08:00
    试过 dumpobject 吗,堆上小对象是什么内容?有 full dump 会好查点。
    0o0o0o0
        7
    0o0o0o0  
       2024-09-26 17:59:47 +08:00
    最好是可以在本地调试状态复现,使用 vs 的快照分析,可以具体查看对象大小以及依赖关系,可以很快速找到根源
    luckybricks9711
        8
    luckybricks9711  
       2024-09-26 18:00:11 +08:00
    查是肯定能查出来的,用 debugdiag 连续抓几个 dump 对着看,才能找出是哪些对象在增加内存,如果还不好定位问题还有 Time Travel Debugging
    sss15
        9
    sss15  
       2024-09-26 18:03:08 +08:00   ❤️ 1
    你只给了一个站 10 分钟后抓取的 dump ,Total 12,315,255 objects, 7,342,657,549 bytes
    你是不是等 10 分钟后再抓一个 dump ,看看总量变化是多少,占用内容变化是多少,这个 dump 应该是堆的内容,只能知道内存中的变量有没有变化,空间占了多少。
    你还需要 dump 一个栈的内容,看看当前执行的方法情况,才能定位到具体代码可能在哪里发生泄漏
    hez2010
        10
    hez2010  
       2024-09-26 20:25:49 +08:00
    如果可以的话建议把 dotnet-dump collect 生成的 dump 文件发给会分析的人去看(里面可能包含你们业务的数据因此要谨慎)。
    shapper
        11
    shapper  
       2024-09-26 20:55:32 +08:00
    奔溃日记和调用栈信息都没有,错误描述都没有,也没有帮你猜错误吧。。。。
    FFFFourwood
        12
    FFFFourwood  
       2024-09-26 21:17:33 +08:00 via iPhone
    我们有个产品从 7 升到 8 内存泄漏严重.…
    我们研究了俩月 无果 ,最后在 azure 上把内存拉高了……
    ZZ74
        13
    ZZ74  
       2024-09-26 21:21:40 +08:00
    没对比,没法看。盲猜问题出在 Core.Models.Order 涉及 UserPricePolicy 逻辑相关。有可能是外包水平的码农写逻辑时无脑查几乎所有数据
    ke1e
        14
    ke1e  
       2024-09-26 21:33:54 +08:00 via Android
    很简单,用 Rust 重写
    locksheep
        15
    locksheep  
       2024-09-26 22:28:12 +08:00
    贴的 Text 里好像有很多 EntityQueryable 查询和 ChangeTracker 追踪检测更改的,不知道是不是因为在查询时一直追踪导致的问题……菜鸡默默围观……
    https://blog.csdn.net/ousetuhou/article/details/135218175
    https://blog.csdn.net/dongnihao/article/details/126475145
    https://learn.microsoft.com/zh-cn/ef/core/change-tracking/change-detection
    csys
        16
    csys  
       2024-09-26 23:24:59 +08:00
    我看了下原帖
    > 查了很多文档 gcdump 都是不会去触发 GC 的

    我不知道你查的什么文档
    但是官方文档是明确有说
    > To walk the GC heap, this command triggers a generation 2 (full) garbage collection

    然后
    > 如果运行 dotnet-gcdump 则能立即恢复正常水平
    gc 能回收,说明不是泄露

    有极大概率是你分配的大对象太多了,大对象在 LOH 里不会被优先回收

    解决方案:
    1. 好好优化下自己的代码,减少巨大对象,会频繁创建的大对象不要 new ,用 ObjectPool
    2. 调整 GCLOHThreshold ,让大对象别进 LOH
    ppxppx
        17
    ppxppx  
       2024-09-26 23:32:53 +08:00 via Android
    @ke1e #14 什么语言都避免不了泄露吧。
    holinhot
        18
    holinhot  
       2024-09-27 03:49:15 +08:00
    @ppxppx PHP 这种可以吧
    HaroldFinchNYC
        19
    HaroldFinchNYC  
       2024-09-27 04:22:24 +08:00
    @Metatron7 这哥们看着确实不错,有点水平
    neilq
        20
    neilq  
       2024-09-27 09:25:00 +08:00
    - 一些配置信息用 redis 做一下缓存,比如 Models.Setting ,Models.WxReplyRule 等,不要每次都从数据库查
    - 我怀疑程序大量使用了 static 变量缓存数据,还是某些表的全量数据
    - Models.Order 存在 select all 到内存中情况 ,WxReplyRule 疑似也存在这个情况
    - 随机数生成算法再优化一下
    aw2350
        21
    aw2350  
       2024-09-27 10:25:34 +08:00
    建议检查 引用的第三方包;再检查类似 闭包 的方法使用导致 内存逃逸
    Smokovsky
        22
    Smokovsky  
       2024-09-27 11:13:02 +08:00
    VS 搞不定就 windbg ,再搞不定就去公众号 @一线码农聊技术,专门搞.net 泄露/异常的,一般最多花个几百就能搞定。
    yazoox
        23
    yazoox  
       2024-09-27 14:15:59 +08:00
    follow, take a look. :-)
    ke1e
        24
    ke1e  
       2024-09-27 16:08:05 +08:00 via Android
    @ppxppx 你只要不 unsafe ,几乎不会出现泄露
    ppxppx
        25
    ppxppx  
       2024-09-27 16:48:47 +08:00 via Android
    @ke1e 我以前用 rust 写过一个转发流量的应用,遇到一个 bug 好像就是 TCP 连接关闭后忘记在 map 释放对象了,导致的结果就是运行一会服务器内存就爆炸了。我觉得这种类型的泄漏没有语言能解决。
    isnullstring
        26
    isnullstring  
       331 天前
    是不是加载太多数据了
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1175 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 23:41 · PVG 07:41 · LAX 16:41 · JFK 19:41
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.