使用WinDbg分析WPF应用程序中OutOfMemoryException的根本原因
我在理解崩溃转储和查找WPF应用程序引发的使用WinDbg分析WPF应用程序中OutOfMemoryException的根本原因,wpf,debugging,memory-leaks,windbg,dump,Wpf,Debugging,Memory Leaks,Windbg,Dump,我在理解崩溃转储和查找WPF应用程序引发的OutOfMemoryException的根本原因方面遇到了一些困难。异常是在应用程序运行数小时后引发的,因此这清楚地表明存在内存泄漏 我的第一步是看!地址-摘要命令: --- Usage Summary ---------------- RgnCount ------- Total Size -------- %ofBusy %ofTotal <unknown> 2043
OutOfMemoryException
的根本原因方面遇到了一些困难。异常是在应用程序运行数小时后引发的,因此这清楚地表明存在内存泄漏
我的第一步是看!地址-摘要
命令:
--- 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)
请注意,共有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[]
004b0890 159 65181140 Free
据我所知,没有一个单一的对象会占用所有的内存。最大的一个只有大约122MB。将所有大小(8500行输出行)相加,得到占用内存的大小(1.1GB)。似乎所有的对象图都以某种方式被复制并添加到内存中,并且从未被释放
!gcroot 6848038c
或!gcroot 6708fd04
检查ValueEntry和System.String的有效性,永不终止,堆栈太大
dumpheap-mt
没有向我展示与我相似的东西<代码>!FinalizeEQUEUE显示有许多对象(超过200万个)已注册以进行终结:
6708a1b8 2401099 38417584 System.WeakReference
Total 2417538 objects
我怀疑当应用程序试图复制对象图并分配新内存时会发生OutOfMemoryException
,但我找不到它的根本原因
问题如何深入到问题的根源(我可以使用windbg的其他命令检查它)。似乎不止一个对象在泄漏,整个对象图也在泄漏。。我是在正确的轨道上,还是我忽略了别的什么?其他假设是什么?对象图复制
您的应用程序使用.NET提供的约1.1 GB虚拟内存。您可以从的输出中看到这一点!eeheap-gc
直接
GC Heap Size: Size: 0x448fde94 (1150279316) bytes.
或者将的值相加!dumpheap-stat
将所有尺寸(8500行输出线)相加得出(1.1GB)
这大致与中显示为
的值相关!地址-摘要
--- Usage Summary ---------------- RgnCount ------- Total Size -------- %ofBusy %ofTotal
<unknown> 2043 58997000 ( 1.384 Gb) 71.43% 69.22%
不幸的是,这65 MB被分成159个较小的区域。要获得其中最大的块,您需要运行!转储堆-mt 004b0890
此外,.NET还可以从Windows(从!address-summary
)获得另外63 MB:
但是最大的数据块只有1.6MB,所以这几乎是无用的:
--- Largest Region by Usage ----------- Base Address -------- Region Size ----------
Free 7752f000 1a1000 ( 1.629 Mb)
因此,很明显,应用程序内存不足
记忆在哪里?
252MB在本机堆中。似乎您正在使用一些本机DLL。虽然目前这似乎不太多,但这一事实可能表明存在固定对象。固定对象不会被垃圾收集。请看的输出!gchandles
以确定这是否是问题的一部分
DLL中有188MB的内存。您可以卸载未使用的本机DLL,但对于.NET程序集,您可能对此无能为力
125MB是堆叠的。默认大小为1MB,应用程序中似乎有125个线程。使用!clrstack
以了解他们正在做什么以及为什么他们还没有完成。可能每个线程都在处理某些事情,但尚未释放对象。如果您可以控制它,那么不要并行启动那么多线程。例如,仅使用8个螺纹,等待螺纹完成后再进行下一项工作
当然,大部分内存是由.NET对象使用的。然而,你得出了一些错误的结论
据我所知,没有一个对象占用了所有的内存。最大的一个只有大约122MB
请注意,没有一个对象占用122 MB ob内存。共有847.783人。这将问题从“为什么这个对象使用这么多内存?”更改为“为什么有这么多内存?”。例如,为什么应用程序需要207.806文本块?它真的显示了这么多文本吗
使用!gcroot
是个好主意。但是,您将其用于方法表的地址,而不是对象:
!gcroot 6848038c
!gcroot 6708fd04
这两个数字都来自的输出!dumpheap-stat
。在中使用它们!gcroot
应该发出如下警告
请注意,6848038c不是有效的对象
相反,!gcroot
仅适用于从获取的单个对象!dumpheap
不带-stat
参数
您可以使用!traveseheap filename.log
将所有对象转储到与兼容的文件中。请注意,CLR探查器无法读取-xml
格式。加载对象信息后,堆图可能是最有用的按钮
要查找OutOfMemoryException的触发器,可以使用
!u
命令。您需要阅读一些MSIL代码来了解它的功能。另见。然而,在您的场景中,我想这是没有用的,因为即使是小对象也可能触发它。除了另一个答案,您可以尝试使用WinDbg扩展可视化内存地址和GC堆也可以尝试使用CLR Profiler,它可以非常容易地为您提供大量复杂的信息。您可以使用导出CLR探查器所需的日志!遍历EAP
。最重要的是,它使显示对象分配图变得非常容易。然而,我很震惊,这可能对你没有帮助-我认为WPF本身存在一些令人讨厌的内存泄漏,环顾四周可能会帮助你找到这个问题。@Luaan不幸的是,我只有崩溃转储,可以进行事后调试。无论如何,谢谢你对CLR提供程序的支持。是!TraverseHeap
特定于CLR探查器的命令?您可以加载由生成的文件!将EAP
遍历到CLR探查器中,因此崩溃
--- Largest Region by Usage ----------- Base Address -------- Region Size ----------
Free 7752f000 1a1000 ( 1.629 Mb)
!gcroot 6848038c
!gcroot 6708fd04