Tom*_*uλa 5 debugging wpf memory-leaks windbg dump
我有一些麻烦来理解崩溃转储并找出OutOfMemoryExceptionWPF应用程序抛出的根本原因.应用程序运行几个小时后抛出异常,这清楚地表明存在内存泄漏.
我的第一步是看看!address -summary命令:
--- Usage Summary ---------------- RgnCount ------- Total Size -------- %ofBusy %ofTotal
<unknown> 2043 58997000 ( 1.384 Gb) 71.43% 69.22%
Heap 152 fcc3000 ( 252.762 Mb) 12.74% 12.34%
Image 1050 bc77000 ( 188.465 Mb) 9.50% 9.20%
Stack 699 7d00000 ( 125.000 Mb) 6.30% 6.10%
Free 518 3f6b000 ( 63.418 Mb) 3.10%
TEB 125 7d000 ( 500.000 kb) 0.02% 0.02%
Other 12 36000 ( 216.000 kb) 0.01% 0.01%
PEB 1 1000 ( 4.000 kb) 0.00% 0.00%
--- Type Summary (for busy) ------ RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_PRIVATE 2186 685b7000 ( 1.631 Gb) 84.14% 81.53%
MEM_IMAGE 1710 f3f3000 ( 243.949 Mb) 12.29% 11.91%
MEM_MAPPED 186 46db000 ( 70.855 Mb) 3.57% 3.46%
--- State Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_COMMIT 3366 73fe7000 ( 1.812 Gb) 93.52% 90.62%
MEM_RESERVE 716 809e000 ( 128.617 Mb) 6.48% 6.28%
MEM_FREE 518 3f6b000 ( 63.418 Mb) 3.10%
--- Protect Summary (for commit) - RgnCount ----------- Total Size -------- %ofBusy %ofTotal
PAGE_READWRITE 1650 5e19e000 ( 1.470 Gb) 75.87% 73.52%
PAGE_EXECUTE_READ 224 bc42000 ( 188.258 Mb) 9.49% 9.19%
PAGE_READWRITE|PAGE_WRITECOMBINE 28 439f000 ( 67.621 Mb) 3.41% 3.30%
PAGE_READONLY 573 3d7b000 ( 61.480 Mb) 3.10% 3.00%
PAGE_WRITECOPY 214 f8f000 ( 15.559 Mb) 0.78% 0.76%
PAGE_EXECUTE_READWRITE 265 d0a000 ( 13.039 Mb) 0.66% 0.64%
PAGE_READWRITE|PAGE_GUARD 357 33b000 ( 3.230 Mb) 0.16% 0.16%
PAGE_EXECUTE_WRITECOPY 55 119000 ( 1.098 Mb) 0.06% 0.05%
--- Largest Region by Usage ----------- Base Address -------- Region Size ----------
<unknown> 78d40000 2350000 ( 35.313 Mb)
Heap 36db0000 fd0000 ( 15.813 Mb)
Image 64a8c000 e92000 ( 14.570 Mb)
Stack 4b90000 fd000 (1012.000 kb)
Free 7752f000 1a1000 ( 1.629 Mb)
TEB 7ede3000 1000 ( 4.000 kb)
Other 7efb0000 23000 ( 140.000 kb)
PEB 7efde000 1000 ( 4.000 kb)
Run Code Online (Sandbox Code Playgroud)
这表明内存非常高.
然后我用eeheap -gc命令查看GC堆大小.它表明堆非常大(1.1GB),表明应用程序的托管部分存在问题.
5fc90000 5fc91000 60c7acd4 0xfe9cd4(16686292)
5a060000 5a061000 5b05e9c0 0xffd9c0(16767424)
56de0000 56de1000 57ddf1c4 0xffe1c4(16769476)
57de0000 57de1000 58ddbbbc 0xffabbc(16755644)
73ff0000 73ff1000 74fe0f5c 0xfeff5c(16711516)
50de0000 50de1000 51dcfa58 0xfeea58(16706136)
5b060000 5b061000 5c05ca54 0xffba54(16759380)
4fde0000 4fde1000 50ddfd8c 0xffed8c(16772492)
Large object heap starts at 0x03921000
segment begin allocated size
03920000 03921000 049013d0 0xfe03d0(16647120)
14850000 14851000 15837380 0xfe6380(16671616)
178d0000 178d1000 1889a3e0 0xfc93e0(16552928)
1a1c0000 1a1c1000 1b1abca8 0xfeaca8(16690344)
40de0000 40de1000 41dc8b48 0xfe7b48(16677704)
42de0000 42de1000 43827170 0xa46170(10772848)
54de0000 54de1000 55dd6d18 0xff5d18(16735512)
Total Size: Size: 0x448fde94 (1150279316) bytes.
------------------------------
GC Heap Size: Size: 0x448fde94 (1150279316) bytes.
Run Code Online (Sandbox Code Playgroud)
请注意,有64个段,每个段大约(16MB).似乎存在一些数据存储在内存中并且从未发布过.
接下来我看看!dumpheap -stat:
65c1f26c 207530 19092760 System.Windows.Media.GlyphRun
65c2c434 373991 20943496 System.Windows.Media.RenderData
68482bb0 746446 26872056 MS.Utility.ThreeItemList`1[[System.Double, mscorlib]]
65c285b4 746448 29857920 System.Windows.Media.DoubleCollection
64c25d58 299568 32353344 System.Windows.Data.BindingExpression
6708a1b8 2401099 38417584 System.WeakReference
67082c2c 1288315 41226080 System.EventHandler
67046f80 1729646 42238136 System.Object[]
64c1409c 206969 52156188 System.Windows.Controls.ContentPresenter
67094c9c 382163 64812664 System.Byte[]
004b0890 159 65181140 Free
64c150d0 207806 72316488 System.Windows.Controls.TextBlock
6708fd04 1498498 97863380 System.String
6848038c 847783 128775772 System.Windows.EffectiveValueEntry[]
Run Code Online (Sandbox Code Playgroud)
据我所知,没有一个占据所有内存的信号对象.最大的一个只有大约122MB.总结所有大小(8500行输出行)给出(1.1GB)占用的内存.似乎所有的对象图都以某种方式重复并添加到内存中并且从未被释放.
本!gcroot 6848038c或!gcroot 6708fd04检查EffectiveValueEntry和System.String如何到达,永远不会结束,堆栈SOOOO大...
dumpheap -mt <address>并没有告诉我一些让我感到震惊的事情.!finalizequeue表明有很多对象(超过2百万)注册完成:
6708a1b8 2401099 38417584 System.WeakReference
Total 2417538 objects
Run Code Online (Sandbox Code Playgroud)
我怀疑OutOfMemoryException当应用程序尝试复制对象图并分配新内存时会发生,但我找不到它的根本原因.
问题如何深入查看问题的根源(我可以使用windbg的其他命令来检查它).因为看起来不只是一个物体在泄漏,而是整个物体图.我是在正确的轨道还是还有其他我忽视的东西?还有其他假设吗?
Tho*_*ler 10
您的应用程序使用.NET的~1.1 GB虚拟内存.你可以!eeheap -gc直接从输出中看到
GC Heap Size: Size: 0x448fde94 (1150279316) bytes.
Run Code Online (Sandbox Code Playgroud)
或者总结价值观!dumpheap -stat.
总结所有尺寸(8500行输出线)给出(1.1GB)
这大致关联到显示值<unknown>在!address -summary.
--- Usage Summary ---------------- RgnCount ------- Total Size -------- %ofBusy %ofTotal
<unknown> 2043 58997000 ( 1.384 Gb) 71.43% 69.22%
Run Code Online (Sandbox Code Playgroud)
没有理由假设整个对象图是重复的.这是正常情况.
目前,.NET已经提交了65 MB的虚拟内存并标记为免费(来自!dumpheap -stat):
004b0890 159 65181140 Free
Run Code Online (Sandbox Code Playgroud)
不幸的是,那些65 MB被分成159个较小的区域.要获得最大块,你需要运行一个!dumpheap -mt 004b0890.
此外,.NET可以从Windows获得另外63 MB(来自!address -summary):
--- Usage Summary ---------------- RgnCount ------- Total Size --------
Free 518 3f6b000 ( 63.418 Mb)
Run Code Online (Sandbox Code Playgroud)
但最大的块只有1.6 MB,所以几乎没用:
--- Largest Region by Usage ----------- Base Address -------- Region Size ----------
Free 7752f000 1a1000 ( 1.629 Mb)
Run Code Online (Sandbox Code Playgroud)
因此,很明显,该应用程序是内存不足.
252 MB是本机堆.看来你正在使用一些原生DLL.虽然目前这似乎不太多,但这一事实可能表明固定物体的存在.固定对象不是垃圾回收.查看输出,!gchandles以确定是否可能是问题的一部分.
188 MB在DLL中.您可以卸载未使用的本机DLL,但对于.NET程序集,您可能无法做很多事情.
堆栈中有125 MB.默认大小为1 MB,您的应用程序中似乎有125个线程.用于!clrstack了解他们正在做什么以及为什么他们还没有完成.潜在地,每个线程都可以处理某些事情,但尚未释放对象.如果你有它在你的控制之下,不要并行启动这么多线程.例如,仅使用8个线程并等待线程完成,然后再完成下一个工作.
当然,.NET对象使用大部分内存.但是,你得出了一些错误的结论.
据我所知,没有一个对象可以占用所有内存.最大的一个只有大约122MB.
请注意,没有一个对象EffectiveValueEntry[]吃122 MB ob内存.其中有847.783.这改变了"为什么这个对象使用这么多内存?"的问题."为什么会有这么多人?" 例如,为什么您的应用程序需要207.806个文本块?它真的显示了这么多文字吗?
使用!gcroot是个好主意.但是,您将它与方法表的地址而不是对象一起使用:
!gcroot 6848038c
!gcroot 6708fd04
Run Code Online (Sandbox Code Playgroud)
这些都是来自输出的数字!dumpheap -stat.使用它们!gcroot应该给出一个警告
请注意,6848038c不是有效对象.
相反,!gcroot仅适用于!dumpheap没有-stat参数的单个对象.
您可以使用!traveseheap filename.log将所有对象转储到与CLR profiler [Codeplex]兼容的文件中.请注意,CLR Profiler无法读取-xml格式.加载对象信息后,Heap Graph可能是最有用的按钮.
要找出OutOfMemoryException的触发器,可以使用该!u命令.您需要阅读一些MSIL代码才能理解它的作用.另请参见如何识别阵列类型.但是,在您的场景中,我猜这没用,因为即使是小对象也可以触发这个.