一:配景
1. 讲故事
微信里有一位朋侪找到我,说他们公司的步调存在内存暴涨题目,本身分析了下没有找到缘故起因,让我看下怎么回事?由于各人都有dump分析根本,以是互换互通上还是很顺遂的,接下来就是上dump分析啦。
二:内存暴涨分析
1. 为什么会内存暴涨
先还是老套路,用 !address -summary 观察下内存分布环境,输出如下:- 0:000> !address -summary
- --- Usage Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
- Free 363 7dfd`e87c7000 ( 125.992 TB) 98.43%
- <unknown> 9276 201`e5858000 ( 2.007 TB) 99.96% 1.57%
- Heap 65 0`2547f000 ( 596.496 MB) 0.03% 0.00%
- Image 1855 0`09d35000 ( 157.207 MB) 0.01% 0.00%
- Stack 93 0`02c00000 ( 44.000 MB) 0.00% 0.00%
- Other 9 0`001de000 ( 1.867 MB) 0.00% 0.00%
- TEB 31 0`0003e000 ( 248.000 kB) 0.00% 0.00%
- PEB 1 0`00001000 ( 4.000 kB) 0.00% 0.00%
- --- State Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
- MEM_FREE 363 7dfd`e87c7000 ( 125.992 TB) 98.43%
- MEM_RESERVE 690 201`2b6d4000 ( 2.005 TB) 99.82% 1.57%
- MEM_COMMIT 10640 0`ec155000 ( 3.689 GB) 0.18% 0.00%
复制代码 从卦中可以看到,总计 3.6G 的总提交内存,看样子都落到了 Unk 地区,最好是托管层吃掉了,否则就贫苦了,接下来使用 !dumpheap -stat 观察,输出如下:- 0:000> !dumpheap -stat
- Statistics:
- MT Count TotalSize Class Name
- ...
- 0179c7715cb0 1,847,901 451,265,880 Free
- 7ffc6e0a2888 2 536,870,960 System.WeakReference<Microsoft.Extensions.DependencyInjection.ServiceProvider>[]
- 7ffc6e0a2260 60,873,978 1,460,975,472 System.WeakReference<Microsoft.Extensions.DependencyInjection.ServiceProvider>
- Total 63,333,893 objects, 2,494,520,292 bytes
复制代码 从卦中可以看到步调中有 6087w 个弱引用,接下来使用 !dumpheap -mt 7ffc6e0a2260 观察下列表详情,然后用 !gcroot 观察其引用根,参考如下:- 0:000> !dumpheap -mt 7ffc6e0a2260
- Address MT Size
- 017988001000 7ffc6e0a2260 24
- 017988001018 7ffc6e0a2260 24
- 017988001030 7ffc6e0a2260 24
- 017988001048 7ffc6e0a2260 24
- 017988001060 7ffc6e0a2260 24
- 017988001078 7ffc6e0a2260 24
- 017988001090 7ffc6e0a2260 24
- 0179880010a8 7ffc6e0a2260 24
- ...
- 017a405f1020 7ffc6e0a2260 24
- 0:000> !gcroot 0179880010a8
- Caching GC roots, this may take a while.
- Subsequent runs of this command will be faster.
复制代码 等了20多分钟都没有出来效果,大概 6kw 的根纵横交错让windbg不堪重负,没有就没撤了,使用内存搜刮法探求上级所属对象。这里就选择 017a405f1020 对象来开刀。- 0:000> !dumpobj /d 17a405f1020
- Name: System.WeakReference`1[[Microsoft.Extensions.DependencyInjection.ServiceProvider, Microsoft.Extensions.DependencyInjection]][]
- MethodTable: 00007ffc6e0a2888
- EEClass: 00007ffc6dbeb4f8
- Tracked Type: false
- Size: 536870936(0x20000018) bytes
- Array: Rank 1, Number of elements 67108864, Type CLASS (Print Array)
- Fields:
- None
- 0:000> s-q 0 L?0xffffffffffffffff 17a405f1020
- 00000179`c95861d0 0000017a`405f1020 03a0dcfa`03a0dcfa
- 0:000> !lno 0000017a`405f1020
- Before: 017a405f1000 32 (0x20) Free
- Current: 017a405f1020 24 (0x18) System.WeakReference<Microsoft.Extensions.DependencyInjection.ServiceProvider>[]
- Error Detected: Object 17a405f1020 has a bad member at offset 12054c00: ??? [verify heap]
- Could not find object after 17a405f1020
- Heap local consistency not confirmed.
- 0:000> !lno 00000179`c95861d0
- Before: 0179c95861c8 32 (0x20) System.Collections.Generic.List<System.WeakReference<Microsoft.Extensions.DependencyInjection.ServiceProvider>>
- Next: 0179c95861e8 24 (0x18) System.WeakReference<Microsoft.Extensions.DependencyInjection.ServiceProvider>[]
- Heap local consistency confirmed.
- 0:000> !dumpobj /d 179c95861c8
- Name: System.Collections.Generic.List`1[[System.WeakReference`1[[Microsoft.Extensions.DependencyInjection.ServiceProvider, Microsoft.Extensions.DependencyInjection]], System.Private.CoreLib]]
- MethodTable: 00007ffc6e0a2340
- EEClass: 00007ffc6dce0000
- Tracked Type: false
- Size: 32(0x20) bytes
- File: D:\xxx\A_api\System.Private.CoreLib.dll
- Fields:
- MT Field Offset Type VT Attr Value Name
- 00007ffc6de328f0 400209f 8 System.__Canon[] 0 instance 0000017a405f1020 _items
- 00007ffc6dc894b0 40020a0 10 System.Int32 1 instance 60873978 _size
- 00007ffc6dc894b0 40020a1 14 System.Int32 1 instance 60873978 _version
- 00007ffc6de328f0 40020a2 8 System.__Canon[] 0 static dynamic statics NYI s_emptyArray
- 0:000> s-q 0 L?0xffffffffffffffff 179c95861c8
- 00000179`c77571d8 00000179`c95861c8 00000000`00000000
- 00000179`c95861b8 00000179`c95861c8 0800004e`00000000
- 0:000> !lno 00000179`c77571d8
- Failed to find the segment of the managed heap where the object 179c77571d8 resides
- 0:000> !lno 00000179`c95861b8
- Before: 0179c9586108 192 (0xc0) Microsoft.Extensions.DependencyInjection.DependencyInjectionEventSource
- Next: 0179c95861c8 32 (0x20) System.Collections.Generic.List<System.WeakReference<Microsoft.Extensions.DependencyInjection.ServiceProvider>>
- Heap local consistency confirmed.
复制代码
根据卦中的图和输出,终于找到了原来是 DependencyInjectionEventSource._providers 负担了全部,接下来的关注点就来到了 DependencyInjectionEventSource。
2. xxxEventSource 是什么
从名字上看和 ETW 变乱有关,接下来用 !eeversion 观察 .net 版本,探求其对应的C#源代码。- 0:000> !eeversion
- 6.0.3624.51421 free
- 6,0,3624,51421 @Commit: f1dd57165bfd91875761329ac3a8b17f6606ad18
- Workstation mode
- SOS Version: 9.0.13.2701 retail build
复制代码
从上面的源代码看,实在也看不出来个以是,毕竟底层的架构我不认识,本着我不是第一个吃螃蟹的人,以是拿关键词在网上索一下,果然 stephentoub 大佬在客岁4月份就发现了这个题目,在 .net10 中做了修复,看形貌是一个优化级的bug,官方链接:https://github.com/dotnet/runtime/issues/114599 截图如下:
修改后的代码如下,果然加了许多的业务逻辑来处置处罚。- [NonEvent]
- public void ServiceProviderBuilt(ServiceProvider provider)
- {
- lock (_providers)
- {
- int providersCount = _providers.Count;
- if (providersCount > 0 &&
- (_survivingProvidersCount is int spc ? (uint)providersCount >= 2 * (uint)spc : providersCount == _providers.Capacity))
- {
- _providers.RemoveAll(static p => !p.TryGetTarget(out _));
- _survivingProvidersCount = _providers.Count;
- }
- _providers.Add(new WeakReference<ServiceProvider>(provider));
- }
- WriteServiceProviderBuilt(provider);
- }
复制代码 从官方形貌来看,就是有人创建了 scope,但后续没有调用 dispose 方法来实时开释,导致框架中的 WeakReference 引用滞留,引发内存暴涨,可以说两者都有责任吧。
办理办法很简单,两种方式:
- 查抄代码里写 BuildServiceProvider 的地方没有即时的 Dispose。
- 升级到 .NET10 ,这是最简单粗暴的方法。
把结论告诉朋侪后,朋侪终于在2天后给我反馈了好消息,盛意情溢于言表!
三:总结
dump之旅是一个补缀工不停自我修炼的过程,必须学会在绝望中探求盼望的本领。
免责声明:如果侵犯了您的权益,请联系站长及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金. |