一:背景1. 讲故事
微信里有一位朋友找到我,说他们公司的程序存在内存暴涨问题,自己分析了下没有找到原因,让我看下怎么回事?由于大家都有dump分析基础,所以交流互通上还是很顺利的,接下来就是上dump分析啦。
二:内存暴涨分析1. 为什么会内存暴涨
先还是老套路,用 !address -summary观察下内存分布情况,输出如下:
0:000> !address -summary
--- Usage Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
Free 3637dfd`e87c7000 ( 125.992TB) 98.43%
Heap 650`2547f000 ( 596.496MB) 0.03% 0.00%
Image 18550`09d35000 ( 157.207MB) 0.01% 0.00%
Stack 930`02c00000 ( 44.000MB) 0.00% 0.00%
Other 90`001de000 ( 1.867MB) 0.00% 0.00%
TEB 310`0003e000( 248.000kB) 0.00% 0.00%
PEB 10`00001000( 4.000kB) 0.00% 0.00%
--- State Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_FREE 3637dfd`e87c7000 ( 125.992TB) 98.43%
从卦中可以看到,总计 3.6G的总提交内存,看样子都落到了 Unk区域,最好是托管层吃掉了,否则就麻烦了,接下来使用 !dumpheap -stat观察,输出如下:
0:000> !dumpheap -stat
Statistics:
MT Count TotalSize Class Name
...
7ffc6e0a2888 2536,870,960System.WeakReference []
7ffc6e0a2260 60,873,9781,460,975,472System.WeakReference
Total 63,333,893objects, 2,494,520,292bytes
从卦中可以看到程序中有 6087w个弱引用,接下来使用 !dumpheap -mt 7ffc6e0a2260观察下列表详情,然后用 !gcroot观察其引用根,参考如下:
0:000> !dumpheap -mt 7ffc6e0a2260
Address MT Size
...
017a405f1020 7ffc6e0a2260 24
Caching GC roots, thismay take a while.
Subsequent runs of thiscommand 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
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 []
Error Detected: Object 17a405f1020 has a bad member at offset 12054c00: ??? [verify heap]
Could not find objectafter 17a405f1020
Heap local consistency not confirmed.
0:000> !lno 00000179`c95861d0
Before: 0179c95861c8 32 (0x20) System.Collections.Generic.List >
Next: 0179c95861e8 24 (0x18) System.WeakReference []
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 40020a2 8 System.__Canon[] 0 staticdynamicstatics NYI s_emptyArray
0:000> s-q 0 L?0xffffffffffffffff 179c95861c8
00000179`c77571d8 00000179`c95861c8 00000000`00000000
0:000> !lno 00000179`c77571d8
Failed to find the segment of the managed heap wherethe object179c77571d8 resides
0:000> !lno 00000179`c95861b8
Next: 0179c95861c8 32 (0x20) System.Collections.Generic.List >
Heap local consistency confirmed.
根据卦中的图和输出,终于找到了原来是 DependencyInjectionEventSource._providers承担了所有,接下来的关注点就来到了 DependencyInjectionEventSource。
2. xxxEventSource 是什么
从名字上看和 ETW 事件有关,接下来用 !eeversion
0:000> !eeversion
6.0.3624.51421free
Workstation mode
SOS Version: 9.0.13.2701retail build
修改后的代码如下,果然加了很多的业务逻辑来处理。
[NonEvent]
publicvoidServiceProviderBuilt(ServiceProvider provider)
{
lock(_providers)
{
intprovidersCount = _providers.Count;
if(providersCount > 0&&
(_survivingProvidersCount isintspc ? (uint)providersCount >= 2* (uint)spc : providersCount == _providers.Capacity))
{
_providers.RemoveAll(staticp => !p.TryGetTarget(out_));
_survivingProvidersCount = _providers.Count;
}
_providers.Add(newWeakReference (provider));
}
WriteServiceProviderBuilt(provider);
}
从官方描述来看,就是有人创建了 scope,但后续没有调用 dispose 方法来及时释放,导致框架中的 WeakReference 引用滞留,引发内存暴涨,可以说两者都有责任吧。
解决办法很简单,两种方式:
检查代码里写 BuildServiceProvider 的地方没有即时的 Dispose。
升级到 .NET10 ,这是最简单粗暴的方法。
检查代码里写 BuildServiceProvider 的地方没有即时的 Dispose。
升级到 .NET10 ,这是最简单粗暴的方法。
把结论告诉朋友后,朋友终于在2天后给我反馈了好消息,好心情溢于言表!
三:总结
dump之旅是一个修理工不断自我修炼的过程,必须学会在绝望中寻找希望的能力。
原创文章,作者:马超,如若转载,请注明出处:http://m.gaochengzhenxuan.com/news/10448.html