debug实战:Unmanaged High Memory非托管高内存
最近又监控到一个高内存的问题,周五下班把系统打开,周末2天没关,周一来看已经涨到5.2G,这次与以往不同,不是.net的内存泄漏,而是非托管引起的。
1. 抓dump,确定高内存的类型
//dump有5.2G,.net的堆只有191M,可以判断是unmanaged high memory
0:000> !eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x0000000159852b88
generation 1 starts at 0x00000001597d26a0
generation 2 starts at 0x0000000003231000
ephemeral segment allocation context: none
segment begin allocated size
0000000003230000 0000000003231000 000000000dad5f38 0xa8a4f38(176836408)
00000001596b0000 00000001596b1000 0000000159db48f8 0x7038f8(7354616)
Large object heap starts at 0x0000000013231000
segment begin allocated size
0000000013230000 0000000013231000 0000000013906b30 0x6d5b30(7166768)
Total Size: Size: 0xb67e360 (191357792) bytes.
------------------------------
GC Heap Size: Size: 0xb67e360 (191357792) bytes.
2. 用windbg找原因
于是不能用sos ext里的命令了,用CodeProject上的这篇文章里的方法试了一下,如下:
//这个命令能看到所有的内存消耗,确实分配了5G多
0:000> !address -summary
Mapping file section regions...
Mapping module regions...
Mapping PEB regions...
Mapping TEB and stack regions...
*** ERROR: Symbol file could not be found. Defaulted to export symbols for DebussyReverie.dll -
Mapping heap regions...
Mapping page heap regions...
Mapping other regions...
Mapping stack trace database regions...
Mapping activation context regions...
--- Usage Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
Free 412 7fe`897c2000 ( 7.994 Tb) 99.93%
Heap 628 1`24c81000 ( 4.575 Gb) 78.18% 0.06%
<unknown> 1217 0`39381000 ( 915.504 Mb) 15.28% 0.01%
Image 2120 0`14561000 ( 325.379 Mb) 5.43% 0.00%
Stack 200 0`04080000 ( 64.500 Mb) 1.08% 0.00%
Other 13 0`001c6000 ( 1.773 Mb) 0.03% 0.00%
TEB 66 0`00084000 ( 528.000 kb) 0.01% 0.00%
PEB 1 0`00001000 ( 4.000 kb) 0.00% 0.00%
--- Type Summary (for busy) ------ RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_PRIVATE 1509 1`59760000 ( 5.398 Gb) 92.24% 0.07%
MEM_IMAGE 2683 0`184d0000 ( 388.813 Mb) 6.49% 0.00%
MEM_MAPPED 53 0`04bfe000 ( 75.992 Mb) 1.27% 0.00%
--- State Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_FREE 412 7fe`897c2000 ( 7.994 Tb) 99.93%
MEM_COMMIT 3267 1`4d29f000 ( 5.206 Gb) 88.96% 0.06%
MEM_RESERVE 978 0`2958f000 ( 661.559 Mb) 11.04% 0.01%
//再查看非托管堆,能看到有1个堆占了4.5G
0:000> !heap -s
LFH Key : 0x000000ff3fbc76ee
Termination on corruption : ENABLED
Heap Flags Reserv Commit Virt Free List UCR Virt Lock Fast
(k) (k) (k) (k) length blocks cont. heap
-------------------------------------------------------------------------------------
Virtual block: 0000000002ca0000 - 0000000002ca0000 (size 0000000000000000)
...
000000001fc30000 00001002 4597824 4568704 4597824 568 296 288 0 1 LFH
...
External fragmentation 23 % (59 free blocks)
-------------------------------------------------------------------------------------
//查看有问题的堆,大小为27d1的某个内存块共有6cc72个,27d1*6cc72=10eb24712(4.5G)
0:000> !heap -stat -h 000000001fc30000
heap @ 000000001fc30000
group-by: TOTSIZE max-display: 20
size #blocks total ( %) (percent of total busy bytes)
27d1 6cc72 - 10eb24712 (99.95)
128 18d5 - 1cb648 (0.04)
2740 11 - 29b40 (0.00)
3e80 1 - 3e80 (0.00)
//用size=27d1过滤,查看每个对象的指针UserPtr
0:000> !heap -flt s 27d1
_HEAP @ 90000
...
_HEAP @ 1fc30000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
0000000025217420 0281 0000 [00] 0000000025217430 027d1 - (busy)
0000000025219c30 0281 0281 [00] 0000000025219c40 027d1 - (busy)
//随便找个对象地址,看被哪里引用了,悲剧的是,不管找哪个,都没有堆栈信息stack trace!
0:000> !heap -p -a 0000000025217430
address 0000000025217430 found in
_HEAP @ 1fc30000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
0000000025217420 0281 0000 [00] 0000000025217430 027d1 - (busy)
3. 用DebugDiag找原因
上面的路目前看起来是走不大通了,于是换Debug大神-美女程序猿-Tess的这篇博文里的方法,改用DebugDiag试试。
- 下载DebugDiag1.2,这是目前最新的版本,已经能支持win7和x64位的系统了。根据你的os选择x86/x64的msi版本并安装。
- 重新启动你的程序,因为这个工具是在跟踪tracking内存分配的过程,所以需要在high memory出现之前就开始监控。
- 打开DebugDiag,选择Add Rule、Native (non-.NET) Memory and Handle,选择要分析的进程,Rule->Status会显示目前处于tracking的状态。
- 执行一段时间、1h 或 1天,转到tab页Processes里右键进程、Create Full Userdump。
- 然后转到Advanced Analysis里选中"Memory Pressure Analyzers"脚本,点击Add Data Files把生成的dump加进去。
- 点击"Start Analysis"就开始分析了,要耐心一点,视dump大小一般需要>10min。
因为要重新启动,下面的dump是我重新抓的,跑了一晚上,大概有1.7G,分析的结果显示是一个DebussyReverie.dll的模块在不停的分配内存。
DebussyReverie.dll is responsible for 1.15 GBytes worth of outstanding allocations. The following are the top 2 memory consuming functions:
DebussyReverie!GetLspGuid+79e: 1.07 GBytes worth of outstanding allocations.
DebussyReverie!GetLspGuid+f31df: 83.04 MBytes worth of outstanding allocations.
Image Name: C:\Program Files\LeagSoft\UniAccess Agent\DebussyReverie.dll
Function DebussyReverie!GetLspGuid+79e
Allocation type Heap allocation(s)
Heap handle 0x00000000`00000000
Allocation Count 114716 allocation(s)
Allocation Size 1.07 GBytes
Leak Probability 81%
//堆栈如下,可惜没能显示从我的代码到问题代码之间的调用关系
Function Source Destination
LeakTrack+13277
DebussyReverie!GetLspGuid+79e
DebussyReverie!GetLspGuid+647
DebussyReverie!GetLspGuid+ea3
DebussyReverie!WSPStartup+431
ws2_32!WahOpenApcHelper+20a
ws2_32!_WSAFDIsSet+e02
ws2_32!WSCInstallProviderAndChains64_32+1971
ws2_32!WSCInstallProviderAndChains64_32+1aa0
ws2_32!WSASendTo+21fc
ws2_32!getsockname+4a
DebussyReverie!PublicService+74b
DebussyReverie!GetLspGuid+a41dd
DebussyReverie!PublicService+2c70
ws2_32!WSApSetPostRoutine+298
ws2_32!WSAConnect+af
System_ni+32f3f2
...
0x7FE8925FEA7
看起来,问题来自公司安装的网络监控软件LeagSoft里的DebussyReverie.dll。大约是下班后服务器断开了,项目里Apache.NMS.ActiveMQ连接出错时调用多线程反复重连,然后被监控软件拦截到后出的错。应该是LeagSoft里的一个Bug,如果能和他们交流一下,应该能进一步确定问题所在,甚至修复这个问题。
debug实战:Unmanaged High Memory非托管高内存的更多相关文章
- debug实战:COM组件GetToSTA导致高内存+GC被阻塞
最近花了好几周解决一个WPF高内存的问题,问题的表象是内存不断增加.未被回收,根源是GC的FinalizeThread被阻塞,导致整个GC挂掉.从以下几步来分析这个问题: 1.用ANTS Memory ...
- C# 托管内存与非托管内存之间的转换
c#有自己的内存回收机制,所以在c#中我们可以只new,不用关心怎样delete,c#使用gc来清理内存,这部分内存就是managed memory,大部分时候我们工作于c#环境中,都是在使用托管内存 ...
- C# 中托管内存与非托管内存之间的转换
c#有自己的内存回收机制,所以在c#中我们可以只new,不用关心怎样delete,c#使用gc来清理内存,这部分内存就是managed memory,大部分时候我们工作于c#环境中,都是在使用托管内存 ...
- C#+无unsafe的非托管大数组(large unmanaged array in c# without 'unsafe' keyword)
C#+无unsafe的非托管大数组(large unmanaged array in c# without 'unsafe' keyword) +BIT祝威+悄悄在此留下版了个权的信息说: C#申请一 ...
- 非等高cell实战(01)-- 实现微博页面
非等高cell实战(01)-- 实现微博页面 学习过UITableView.AutoLayout以及MVC的相关知识,接下来通过一个微博页面实战来整合一下. 首先看一下效果图: 需求分析 此页面为非等 ...
- 编写高质量代码改善C#程序的157个建议——建议50:在Dispose模式中应区别对待托管资源和非托管资源
建议50:在Dispose模式中应区别对待托管资源和非托管资源 真正资源释放代码的那个虚方法是带一个bool参数的,带这个参数,是因为我们在资源释放时要区别对待托管资源和非托管资源. 提供给调用者调用 ...
- 非等高cell实战--实现微博页面
代码地址如下:http://www.demodashi.com/demo/11639.html 前言 学习过UITableView.AutoLayout以及MVC的相关知识,接下来通过一个微博页面实战 ...
- 在VS2010上使用C#调用非托管C++生成的DLL文件
背景 在项目过程中,有时候你需要调用非C#编写的DLL文件,尤其在使用一些第三方通讯组件的时候,通过C#来开发应用软件时,就需要利用DllImport特性进行方法调用.本篇文章将引导你快速理解这个调用 ...
- C# 托管和非托管混合编程
在非托管模块中实现你比较重要的算法,然后通过 CLR 的平台互操作,来使托管代码调用它,这样程序仍然能够正常工作,但对非托管的本地代码进行反编译,就很困难. 最直接的实现托管与非托管编程的方法就是 ...
随机推荐
- array_merge注意细节
array_merge:合并一个或多个数组,一个数组中的值加在前一个数组的后面,返回的新数组作为结果 如果输入的数组中有相同的字符串键名,则该键名后面的值覆盖前面的,如果数组包含相同的数字键名,后面的 ...
- 从简单需求到OLAP的RANK系列函数
同事问了一个非常简单的问题,怎么取出每个partition里面另外一个列的最小值? create table t1 (int c1, int c2); 假如按照c2分区,0-10,10-20,20 ...
- kali无法输入中文
已经装了fcitx,之前都是可以用的,今天启动时发现无法切换出中文输入法 用 Fcitx config tool查看发现输入法表里面是空的 最后发现是启动时fcitx进程没自动运行,加入自动运行后重启 ...
- Process and Thread
A process is a completely independent program that has its own address space, while a thread is a se ...
- C# 的Brush 及相关颜色的操作 (并不是全转)
C# 的Brush 及相关颜色的操作 2013-12-13 14:08 4977人阅读 评论(0) 收藏 ...
- 关于treeview手动添加的方法
1.首先判断有没有父节点,有父节点的,NEW一个父节点然后增加:没有父节点就选当前的节点 treeView2.Nodes.Add(newChildNode); 2.父节点的判断可以用leveL来判断 ...
- asp.net 分页-自己写分页控件
去年就发表过asp.net 分页-利用后台直接生成html分页 ,那种方法只是单纯的实现了分页,基本不能使用,那时就想写个自己的分页控件,无奈能力有限.最近有点时间了,就自己做出了这个分页控件.我承认 ...
- noi 2985 数字组合
题目链接: http://noi.openjudge.cn/ch0206/2985/ 2985:数字组合 查看 提交 统计 提问 总时间限制: 1000ms 内存限制: 65536kB 描述 有n个正 ...
- python 学习笔记十三 JQuery(进阶篇)
jQuery 是一个 JavaScript 库. jQuery 极大地简化了 JavaScript 编程. 安装jQuery 有两个版本的 jQuery 可供下载: Production versio ...
- bootstrap-validator验证问题总结
bootstrap-validator是一个优秀的验证器,使用中遇到如下问题,总结如下: 1.<button type="submit" name="submit2 ...