当前位置: 首页 > news >正文

记一次 .NET 某光电成像后端解析系统 内存暴涨分析

一:背景

  1. 讲故事
    前些时间有位朋友找到我,说他们部署在linux上的系统内存占用比较高,领导让他找原因,由于自身的技术上限一直没找到,让我帮忙看下,让朋友通过 dotnet-dump 或者 procdump 从生产上抓一个下来,既然dump到手,那就进入分析环节啦。

二:内存暴涨分析

  1. 为什么会暴涨
    由于是linux上的.net,原来的 !address -summary 就彻底失去功效了,使用高版本的sos自带的全平台替换版 !maddress 去搞定,输出结果如下:

0:000> !maddress
0:000> !maddress
±-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Memory Kind | StartAddr | EndAddr-1 | Size | Type | State | Protect | Image |
±-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Stack | ffc81c7a0000 | ffc81cfa0000 | 8.00mb | MEM_PRIVATE | MEM_COMMIT | PAGE_READWRITE | |
| Stack | ffc81cfb0000 | ffc81d7b0000 | 8.00mb | MEM_PRIVATE | MEM_COMMIT | PAGE_READWRITE | |
| Stack | ffc81e7e0000 | ffc81efe0000 | 8.00mb | MEM_PRIVATE | MEM_COMMIT | PAGE_READWRITE | |
| Stack | ffc81eff0000 | ffc81f7f0000 | 8.00mb | MEM_PRIVATE | MEM_COMMIT | PAGE_READWRITE | |
±------------------------------------------------------------------------+
| Memory Type | Count | Size | Size (bytes) |
±------------------------------------------------------------------------+
| Stack | 314 | 3.65gb | 3,918,856,192 |
| GCHeap | 384 | 3.02gb | 3,240,099,840 |
| PAGE_READWRITE | 1,151 | 175.37mb | 183,889,536 |
| Image | 622 | 115.80mb | 121,428,352 |
| LowFrequencyHeap | 33 | 6.31mb | 6,619,136 |
| HighFrequencyHeap | 10 | 6.19mb | 6,488,064 |
| LoaderCodeHeap | 7 | 5.00mb | 5,242,880 |
| PAGE_READONLY | 131 | 4.26mb | 4,466,176 |
| PAGE_EXECUTE_WRITECOPY | 7 | 704.00kb | 720,896 |
| ResolveHeap | 1 | 512.00kb | 524,288 |
| DispatchHeap | 1 | 384.00kb | 393,216 |
| StubHeap | 1 | 192.00kb | 196,608 |
| IndirectionCellHeap | 1 | 64.00kb | 65,536 |
| CacheEntryHeap | 1 | 64.00kb | 65,536 |
| LookupHeap | 1 | 64.00kb | 65,536 |
| HostCodeHeap | 1 | 64.00kb | 65,536 |
±------------------------------------------------------------------------+
| [TOTAL] | 2,666 | 6.97gb | 7,489,187,328 |
±------------------------------------------------------------------------+

看到卦中的这些信息,秤砣终于落地了,总计吃了6.97G的内存,主要都是被 Stack 和 GCHeap 给吃掉了。

  1. 为什么 Stack 吃了这么多
    熟悉 linux 的朋友应该知道,默认情况下 Stack 会吃掉 8M 的内存,这在上面的 items 上也能看出究竟,不过有点讽刺的是在微软的官方MSDN上居然没找到 DOTNET_DefaultStackSize 变量的解释,只在一些野路子中发现了端倪,下面图中小哥的大胡子我咋看起来 quite sexual, 截图如下:

image
image

搞清楚前因后果之后,处理起来就比较简单了,使用环境变量即可,不过这东西也有自己的限制,设置不了主线程

DOTNET_DefaultStackSize=180000
如果将StackSize从 8M -> 1.5M,那 Stack 所侵占的内存就彻底搞定啦。

  1. 为什么 GCHeap 吃了这么多
    要想找到这个问题的答案,直接 !eeheap -gc 观察托管堆即可。

0:000> !eeheap -gc

DATAS =

Number of GC Heaps: 128


Heap 126 (0000aaacefcfe750)
generation 0 starts at ffed4400c468
generation 1 starts at ffed4400c450
generation 2 starts at ffed44000000
ephemeral segment allocation context: none
Small object heap
segment begin allocated committed allocated size committed size
ffed43ff0000 ffed44000000 ffed4400c480 ffed44f80000 0xc480 (50304) 0xf80000 (16252928)
Large object heap starts at fff5a4000000
segment begin allocated committed allocated size committed size
fff5a3ff0000 fff5a4000000 fff5a44da1e8 fff5a4590000 0x4da1e8 (5087720) 0x590000 (5832704)
Pinned object heap starts at fffda4000000
segment begin allocated committed allocated size committed size
fffda3ff0000 fffda4000000 fffda4000018 fffda4010000 0x18 (24) 0x10000 (65536)

Heap 127 (0000aaacefd2fc70)
generation 0 starts at ffed84028fe8
generation 1 starts at ffed84028d90
generation 2 starts at ffed84000000
ephemeral segment allocation context: none
Small object heap
segment begin allocated committed allocated size committed size
ffed83ff0000 ffed84000000 ffed84029000 ffed84fa0000 0x29000 (167936) 0xfa0000 (16384000)
Large object heap starts at fff5b4000000
segment begin allocated committed allocated size committed size
fff5b3ff0000 fff5b4000000 fff5b4668240 fff5b4810000 0x668240 (6718016) 0x810000 (8454144)
Pinned object heap starts at fffdb4000000
segment begin allocated committed allocated size committed size
fffdb3ff0000 fffdb4000000 fffdb4004030 fffdb4010000 0x4030 (16432) 0x10000 (65536)

GC Allocated Heap Size: Size: 0x3577ef58 (897052504) bytes.
GC Committed Heap Size: Size: 0xc1200000 (3240099840) bytes.

从卦中数据看,有经验的朋友马上就条件反射出这是个啥问题,对,我经常说的内存黑洞,即用handful的数据直接撬开了数十倍甚至数百倍的自身内存,比如上面 897M 撬开了 3.24G。

虽然程序中有快进快出的现象,但这里也有一个不可忽视的客观条件,即程序中居然有 128 个heap,这就说明机器是 128core的,哈哈,这么多核心的cpu,我估计内存也不小,一查果然是 254G 内存,某些行业真的是高富帅哈。。。输出如下:

0:000> dp libcoreclr!SVR::gc_heap::total_physical_mem L1
0000fffe4b0b71f8 0000003f88bc0000
0:000> ? 0000003f88bc0000 /0n1024/0n1024/0n1024 Evaluate expression: 254 = 00000000000000fe

再次观察托管堆你会发现 allocated size 和 committed size 相距不像我之前分析的程序会有那么大,这里也仅仅10多M左右,结果坏就坏在核心数太多,直接翻了128倍,导致了最后的的悲剧发生。

所以这个问题的解决思路也比较简单,两个路子。

升级到 .NET10,使用自带的 DATAS 机制。
修改 GC 为 Workstation 模式。
说实话这个内存黑洞在 .NET6 时代时,我在分析dump时就多次遇到,向gc架构师 Maoni 大佬吐槽过,终于这个问题在 .NET8 中得到了很大的重视,并在 .NET10 中默认开启。

三:总结
这次内存爆高的事故更多的还是 Linux 和 .NET 的内部设计机制综合导致的,了解这些 externel component 的性格秉性,对我们调试师非常重要。

http://www.jsqmd.com/news/1228639/

相关文章:

  • 泸州业主必看!2026筑宅安本地化防水,告别反复渗漏 - 筑宅安
  • 【JAVA毕设源码分享】基于springboot可追溯果园生产过程管理系统的设计与实现(程序+文档+代码讲解+一条龙定制)
  • 时间序列算法2---大模型因果推断如何接入现有告警平台
  • 免费AI语音克隆终极指南:10分钟打造专属声音的完整方案
  • 机构调研信息价值挖掘与投资逻辑构建
  • 审计全量数据怎么查异常?统计离群、关联规则与图异常三种方法的工程对比
  • Label Studio终极指南:如何在5分钟内搭建你的多模态AI数据标注平台
  • 安卓与iOS微信昵称特殊符号输入全攻略
  • 2026年白帽GEO优化服务商推荐:E-E-A-T白帽内容生产SOP哪家强? - GEORANK
  • GPT-3-Encoder核心原理解析:深入理解字节对编码(BPE)算法实现
  • Theme Toggles未来展望:路线图、新功能规划与技术演进
  • David深度解析:10个技巧让你的npm依赖管理更高效
  • 实况窗:从被动查看到主动提醒,让信息“自己找人”
  • Python虚拟环境创建与配置
  • sandbox-sdk安全最佳实践:保护边缘代码执行环境的7个关键策略
  • 2026毓典奢品汇|北京高端名包回收行业专业标准与正规门店指南 - 名表行情观察
  • 2026 永康装修口碑榜单|深耕多年,永康南国鼎峰装饰凭专业施工与诚信服务收获永康业主一致好评 - 商业先知
  • 职场与专业场景下的英文实力表达指南
  • 微信昵称设置上标数字的完整指南
  • Adafruit ADS1X15 终极指南:快速掌握12位/16位ADC芯片驱动开发
  • Google Ads Python库在生产环境中的部署与监控:确保广告API集成稳定运行的完整指南
  • 鸿蒙新特性 | 图片怎么显示——Image 组件那些坑
  • ComfyUI Manager完整指南:高效管理自定义节点的专业解决方案
  • 【Agentic RL / 强化学习 / OPD】OpenClaw-RL 源码阅读笔记 --- (8)--- Environment
  • 2026年C# .NET技术全景:跨平台开发与工业自动化实战
  • AI数据分析不是“加模型”,而是重构业务流(附能源/物流/教育行业流程再造对照图谱)
  • Claude AI深度整合Office三件套提升办公效率
  • 2026年暑运高峰应对与智慧出行全攻略
  • 2026 郑州厨卫渗水维修怎么选?本地防水服务商施工、材料、售后全方位对比 - 资讯在线
  • PKUAutoElective多账号选课指南:如何高效管理多个选课任务