windbg分析.net内存泄漏
2020-02-26 05:24:01    63    0    0
lion

1、安装windbg 

    http://windbg.org/


2、符号加载问题 

 


设置两个环境变量: 
_NT_SYMBOL_PATH=srv*D:\symbo*http://msdl.microsoft.com/download/symbols;cache*D:\symbo 
_NT_SYMBOL_PROXY=ip:port 
第一个为symbol服务器和缓存路径 
第二个为代理(有时候必需挂代理,即使本地能访问microsoft) 

3、分析

引用自:https://www.cnblogs.com/50614090/p/9553740.html

2.1  查看GC堆的内存占用情况

Net程序大部分内存泄漏是由于没有及时垃圾回收导致的,就从GC堆开始分析。

!eeheap -gc

 

统计一下,有8个GC堆(因为有8个CPU核),每个堆大概在1个G左右的大小,GC堆加起来大概8个G左右。对比一下dump文件的大小为8.86个G,这个信息也就很明确了,内存都被GC堆给占用了。

 

 

挑选heap 0来分析,发现900多M内存都在第二代里,说明对象被根引用了,没有被及时释放,导致内存泄漏。我们重点分析第二代里的对象。

2.2 分析GC堆 heap 0的第二代对象

分析所有堆会比较慢,我们只分析heap0的第二代对象。

 !dumpheap -stat 00000218c75d1000 0000021902a69720

 

发现Kingdee.BOS.JSON.JSONArray,System.Object[],System.String 这三个类型占了700多M内存,就重点看上面的三个类型。

 

2.2.1      分析System.String

分析一下是否有大于200个字节的长字符,看看是不是超大的字符串占用了大量内存:

!dumpheap -mt 00007ffdb9386948 -stat  -min 200 00000218c75d1000 0000021902a69720

 

 发现大字符串的数量很少,才占用3M空间,推测应该都是一些小的字符串对象,由于string对象数量有1000万左右,如果继续分析string类型,收获会比较小,搞不清楚到底是那些string对象引起的占用大量内存的。String类型肯定是被其他类型引用的, System.Object[]也是类似,所以我们重点分析Kingdee.BOS.JSON.JSONArray

 

2.2.2       分析Kingdee.BOS.JSON.JSONArray对象

分析Kingdee.BOS.JSON.JSONArray的方法表:!dumpheap -mt 00007ffd5c24a068  00000218c75d1000 0000021902a69720

 

发现了有大量的40个字节的对象,ctrl+break中断一下,随机挑选一个对象,看看里面到底是什么内容。

 

查看Kingdee.BOS.JSON.JSONArray的对象: !do 00000218cc5002a0

 

继续查看明细项数组:items: !da 00000218cc575d60

 

 

是一个object[]数组,看起来是Kingdee.BOS.JSON.JSONArray对象引用了object[]数组。

继续查看数组中的对象:!do 00000218cc50b438

 

 

发现数组的项是一个Kingdee.BOS.JSON.JSONArray对象

继续查看对象的items数组:!da 00000218cc50b490

 

查看最终的明细项

!do 00000218cc50b310

!do 00000218cc50b3a0

能看到下面的字符串:“ABCFPZLB”,“ABC分配组列表”等字符串。

2.2.3       查找Kingdee.BOS.JSON.JSONArray根

找到了出问题的明细内存内容后,我们还需要找到出问题的代码到底在哪?看看能从根引用上能不能找到更多的线索。可以看看Kingdee.BOS.JSON.JSONArray对象到底是被那个根引用?

!gcroot -nostacks 00000218cc5002a0

 

Kingdee.BOS.JSON.JSONArray对象被缓存了,在gc句柄表被固定住了,不能被垃圾回收器回收,所以导致内存泄漏了。由于根对象列表没有发现一些更有价值的类型,我们只能通过上面的二个线索来推测问题.

线索1、“ABCFPZLB”,“ABC分配组列表”等字符串 看起来像菜单编码、名称

线索2、这些字符串被缓存了

 

推断出:可能菜单信息的缓存出了问题。

 

我们也可以看看堆栈信息,运气好的话,能从堆栈中看到一些可疑的堆栈。查看所有线程的堆栈:~*e !clrstack

 

在这个案例中,还真是发现了可疑的堆栈

 

GetMenuArrayForCache这个方法没有命中缓存。查看源码后发现,这个缓存的key有问题,命中率很低,导致大量重复的数据被缓存。





基础命令:
.load Psscor4/amd64/amd64/psscor4.dll 加载psscor4
.load SOS/SOS.dll
.sympath 设置符号路径
.cls 清屏
version 查看版本信息
lm 列出加载模块
!help 显示命令帮助
!help EEHeap 显示EEHeap命令帮助
!EEVersion 显示公共语言运行时版本

内存状态:

!EEHeap -GC 显示托管堆统计信息
!EEHeap -loader 显示加载程序数据结构统计信息
!DumpHeap -stat 显示垃托管堆各类型统计信息
!DumpHeap -type Free -stat 显示所有碎片类型统计信息
!DumpHeap -type System.String -min 150 -max 200 显示所有System.String类型 -min -max 字节统计信息
!DumpHeap -min 85000 -stat 显示大对象统计信息
!DumpHeap -mt 选项仅列出与指定的 MethodTable 结构对应的那些对象
!DumpHeap -mt 00000000022245b0 -min 85000 查看MT 00000000022245b0中大对象
!DumpHeap -stat 023e1000 033db630 按地址统计
!DumpArray 显示数组对象
!DumpObj (!do) 显示有关指定地址处的对象的信息
!ObjSize 显示指定对象的大小
!DumpStackObjects (!dso) 显示在当前线程内找到的所有托管对象
!GCRoot 显示有关对指定地址处的对象的引用(或根)的信息。
!CLRUsage 显示托管堆统计信息(GC堆大小,提交内存,虚拟内存),psscor4的扩展命令
!DumpMT 显示有关指定地址处的方法表的信息。
!DumpMT -MD 显示有关指定地址处的方法表所有方法的列表。
!address -summary 显示最大可用区域
!vmstat 最大可用区域是 MAXIMUM 列中的最大值

线程调用:

!ThreadPool 显示有关托管线程池的信息,包括队列中工作请求的数目、完成端口线程的数目和计时器的数目
!Threads 显示进程中的所有托管线程
!Threads -live 选项显示与活动线程关联的线程
!Threads -pecial 选项显示由 CLR 创建的所有特殊线程
!ThreadState 显示线程的状态。 value 参数为 Threads 报告输出中的 State 字段的值。
~54s 转到54线程
!CLRStack 提供当前托管代码的堆栈跟踪。
!CLRStack -p 选项显示托管函数的参数。
!CLRStack -l 选项显示有关帧中的局部变量的信息。
!DumpStack 显示堆栈跟踪 包括非托管。
!DumpStack -EE 命令仅显示托管函数。
!EEStack 对一个进程中的所有线程运行 DumpStack 命令。
k 显示当前线程的call stack
kb 显示当前线程的call stack
~*kb 显示所有线程的call stack 可以 寻找线程中触发GC的函数(mscorwks!SVR::GCHeap::GarbageCollectGeneration)
!ASPXPages 显示当前处理的HttpContext,psscor4的扩展命令
!SyncBlk 显示同步块

其它:
!runaway 显示线程cpu时间
vertarget 查看系统运行时间
!PrintException (!pe) 显示在当前线程上引发的最后一个异常
!address 命令显示某一地址上的页信息
!SaveModule 将加载到内存中指定地址的图像写入指定文件,lm 列出的
!SaveModule 081f0000 d:\\commandobject.dll
!FinalizeQueue 显示所有已进行终结注册的对象。
!GCHandles 显示有关进程中的垃圾回收器句柄的统计信息。

S 可以搜索内存 在内存中搜索sina.com: s –u 0012ff40 L?8000000 “sina.com”
r 显示寄存器的信息
d 显示内存地址上的值 使用d命令显示esp寄存器指向的内存,默认为byte: d esp
用dd命令直接指定054efc14地址,第二个d表示用DWORD格式: dd 054efc14

域,程序集,类
!DumpDomain 枚举在指定的 AppDomain 对象地址内加载的每个 Assembly 对象。若在调用 DumpDomain 命令时不提供任何参数,则将列出过程中的所有 AppDomain 对象
!DumpAssembly 显示有关程序集的信息。DumpAssembly 命令将列出多个模块(如果存在)。
!DumpModule  显示有关指定地址处的模块的信息。 可以使用 DumpDomain 或 DumpAssembly 命令检索模块的地址
!DumpModule [-mt] 选项显示模块中定义的类型和模块所引用的类型
!FindAppDomain 确定指定地址处的对象的应用程序域

!IP2MD <Code address> 显示已 JIT 编译的代码中指定地址处的 MethodDesc 结构。
!DumpMD <MethodDesc address>
!U <MethodDesc address> | <Code address> 显示由方法的 MethodDesc 结构指针或方法体内的代码地址指定的托管方法的反汇编(带有批注)

 

Pre: nuget相关

Next: K8s

63
目录