使用Windbg+sos+sosex从内存转储详细分析对象引用,排查.NET服务应用内存暴增

作者:V君 发布于:2018-8-22 12:37 Wednesday 分类:填坑经验

TL;DR

1) 准备:先载入转储

 如果缺少dll, 去 https://sos.debugging.wellisolutions.de/ 找

 下来放windbg旁边,然后重新载入.

2) 初始化:载入sos和sosex [.loadby sos mscorwks],[.load sosex],首次要执行[!bhi]

3) 对象统计:用sos的[!dumpheap -stat]或者sosex的[!sosex.mfrag -stat]获取结果

4) 枚举对象:用sos的[!dumpheap -type <上结果类名>]就能刷出

  sosex的[mfrag -mt:类名]如果能用就可以直接点击链接, 这次不知道为啥不工作.

5) 查找引用:用sosex的[!refs <上结果地址>]

  顺着地址链接一路跟踪就能定位内存占用的代码位置.

 

 

必须扯:

 

依旧是折磨人的老项目, 在一处数据错误被修正之后, 负载急剧上升, 

原来服务应用程序一直都不正常, 不完整运行.

按照一如既往的套路, 首先抓转储, 打包回来慢慢分析. 

然而这次和之前的状况不太一样, 还遇到了点麻烦.

 

拿起windbg载入转储一把梭哈[.loadby sos mscorwks],[!dumpheap -stat]然后碰壁:

> Failed to load data access DLL, 0x80004005

> verify that the file mscordacwks___.dll is on your symbol path

只好转战sosex试试了,重新载入转储来一把[.load sosex],按提示接着运行[!bhi]然后还是挂了

> Unable to initialize .NET data interface. 

 Version 2.0.50727.5485 of mscordacwks.dll is required.

> Locate and load the correct version of mscordacwks.dll.

 See documentation for the .cordll command.

见到2.0的运行时版本也不奇怪,毕竟老项目用的是3.5.

版本号的前三段都熟悉, 然而最后的5485使我一脸蒙逼.

又按照提示执行了[.cordll]得到更懵逼的输出

> CLR DLL status: ERROR: Unable to load DLL mscordacwks_AMD64_AMD64_2.0.50727.5485.dll, Win32 error 0n87

用everything搜了一把文件名,发现机器上确实没有精确到最后一段版本号的dll, 

然而服务器上却有.

 

把版本号丢进咕狗找了一下找到一个奇怪的站点 https://sos.debugging.wellisolutions.de

根据上面的提示,把对应dll下载到符号目录.重新载入转储走套路1.然而并卵,还是一样的提示.

只好丢到windbg.exe旁边了, 然后再次重新载入.

  -- 哎, 成功啦! 进入BUSY状态好一会儿. 然后一堆类名刷屏.

 

再试试sosex看看,毕竟这货更好用些.

嗯, 堆索引命令[!bhi]顺利运行起来,接着运行[!sosex.mfrag -stat]统计内存对象

跑了一小会儿之后, 也把东西刷出来了. 两者的内存对象统计结果稍稍有些不同.

但这次占据内存绝大部分的不是字符串了,

是具体类型, 不能再无脑刷字符串找线索.


咕狗一下进一步用法吧.

 

将[sosex windbg memory]喂给咕狗,吐出[MSDN博客文章],文章里讲的是sos,没ex.

但也试着按照文章的步骤走走看.

无脑按照文章步骤到[!VerifyHeap]命令,发现持续BUSY好久都没反应.

只好放置play,继续找sosex的方法, windbg是可以多开的.

 

找到了sosex的帮助命令[!sosex.help]但这时sos那边的堆校验已经完成且未发现错误,

可以继续往下走啦.

原来[!dumpheap]可以指定type参数,指定了统计结果最多的类型之后如同预期的一样开始刷屏.

在sosex那边得用参数mt指定筛选类型, 有点意外的是她跑起来比sos花更多时间,

不管他, 回到sos继续看看文章怎么操作.

文章里接着提到了[!do]命令, 用于将指定地址的对象成员展开, sos就到这里吧.


从类名就知道是什么东西了,现在我想知道它们被堆积在哪里,

继续咕狗到博客园的一篇文章,提到了引用查找.

使用[!refs]命令,将内存地址作为参数, 他就能帮你找到引用它或者它引用了的对象.


顺藤摸瓜总算是找到了线索. 摸索结束,接下来该去填坑了.


 

 

 

 

 

 

标签: 软件开发 C# 调试技术 windbg 软件故障诊断 sosex

引用地址:

发表评论:

Powered by emlog 去你妹的备案 sitemap