我有一个使用C#和WPF构建的应用程序,在Windows 8上运行。C#代码使用Interop调用外部C ++ dll。经过一系列操作,内存使用量高达2GB,因此怀疑存在内存泄漏。我创建了该过程的转储,并尝试使用WinDbg通过命令!address -summary
对其进行分析,得到以下消息:
--- Usage Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
Free 482 7ff`4d11b000 ( 7.997 Tb) 99.97%
<unknown> 1208 0`7573d000 ( 1.835 Gb) 65.64% 0.02%
Heap 1664 0`1e1ab000 ( 481.668 Mb) 16.82% 0.01%
Image 1294 0`19f98000 ( 415.594 Mb) 14.52% 0.00%
Stack 261 0`053ce000 ( 83.805 Mb) 2.93% 0.00%
Other 23 0`001d8000 ( 1.844 Mb) 0.06% 0.00%
TEB 87 0`000ae000 ( 696.000 kb) 0.02% 0.00%
PEB 1 0`00001000 ( 4.000 kb) 0.00% 0.00%
--- Type Summary (for busy) ------ RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_PRIVATE 2634 0`922ae000 ( 2.284 Gb) 81.69% 0.03%
MEM_IMAGE 1787 0`1b38d000 ( 435.551 Mb) 15.21% 0.01%
MEM_MAPPED 90 0`05807000 ( 88.027 Mb) 3.07% 0.00%
--- State Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_FREE 509 7ff`4d1ae000 ( 7.997 Tb) 99.97%
MEM_COMMIT 3346 0`9205e000 ( 2.282 Gb) 81.61% 0.03%
MEM_RESERVE 1165 0`20de4000 ( 525.891 Mb) 18.37% 0.01%
--- Protect Summary (for commit) - RgnCount ----------- Total Size -------- %ofBusy %ofTotal
PAGE_READWRITE 1577 0`73295000 ( 1.799 Gb) 64.36% 0.02%
PAGE_EXECUTE_READ 183 0`1212e000 ( 289.180 Mb) 10.10% 0.00%
PAGE_READONLY 941 0`082f9000 ( 130.973 Mb) 4.57% 0.00%
PAGE_READWRITE|PAGE_WRITECOMBINE 24 0`03aad000 ( 58.676 Mb) 2.05% 0.00%
PAGE_EXECUTE_READWRITE 131 0`00bcc000 ( 11.797 Mb) 0.41% 0.00%
PAGE_READWRITE|PAGE_GUARD 87 0`00191000 ( 1.566 Mb) 0.05% 0.00%
PAGE_NOACCESS 399 0`0018f000 ( 1.559 Mb) 0.05% 0.00%
<unknown> 1 0`00004000 ( 16.000 kb) 0.00% 0.00%
PAGE_EXECUTE 2 0`00003000 ( 12.000 kb) 0.00% 0.00%
PAGE_WRITECOPY 1 0`00002000 ( 8.000 kb) 0.00% 0.00%
--- Largest Region by Usage ----------- Base Address -------- Region Size ----------
Free a1`9f910000 754`5f4fc000 ( 7.330 Tb)
<unknown> a1`4fc30000 0`17ffc000 ( 383.984 Mb)
Heap a1`1c421000 0`00dff000 ( 13.996 Mb)
Image 0`6c991000 0`0174e000 ( 23.305 Mb)
Stack a1`160c0000 0`000fb000 (1004.000 kb)
Other a1`4e480000 0`00181000 ( 1.504 Mb)
TEB 7f5`fee0c000 0`00002000 ( 8.000 kb)
PEB 7f5`ff14c000 0`00001000 ( 4.000 kb)
为什么Free块这么大?在摘要中,有什么线索可能会导致内存泄漏?
答案 0 :(得分:1)
您所描述的是一个常见问题,不仅对于测试人员,对于开发人员也是如此。在您了解整个图片之前,您永远都不知道真正有多少内存可用。
我用一个酒吧老板的比喻来解释这个问题。那个酒吧老板参加了一个非常大的聚会。他没有足够的眼镜,因此与玻璃租赁公司联系。那家玻璃租赁公司有8000副玻璃要出租。
酒吧老板定购2000杯。聚会开始时,所有眼镜都是空的。但是谁能发表这个声明呢?从玻璃租赁公司的角度来看,已经淘汰了2000杯-无法再订购。因此,玻璃租赁公司将它们视为“未使用”,而酒吧老板则将其视为“未使用”。
聚会开始,侍者接到命令,酒吧老板调酒。在某个时间点,酒吧老板给了500杯服务生。从他的角度来看,有1500杯是空的,有500杯是空的。
但是,这500杯可能还没装满。一些客人可能非常口渴,已经倒空了眼镜。因此,实际上,这500个眼镜中有200个可能是空的,只有300个杯子装满了。
所以,这取决于您问谁:
程序的虚拟内存也是如此,只是参与者不同:
使用!address
询问操作系统。如果它说“我为.NET分配了1.8 GB”,那么这是有助于理解现实的正确陈述。
但是,您不知道.NET怎么说。您需要问一下。 !dumpheap -stat
将是一个适当的问题。该答案将包括一些有关Free
类型的对象的声明。
即使您看到{。{1}}(被.NET视为“正在使用”),从应用程序逻辑的角度来看,这1 MB也可能是部分空白。如果那个byte[1000000]
是一个缓冲区,那么通常会有一些byte[]
属性告诉应用程序实际使用了多少缓冲区。其余的可以视为“免费”。
结论
您需要在正确的级别上询问正确的问题,以了解是否正在使用内存。
为什么Free块这么大?
因为那是玻璃租赁公司的答案。有很多眼镜可以租用(还剩6000个)。
在摘要中,有什么线索可能会导致内存泄漏?
泄漏表示增长。您无法从单个快照中识别它。您需要随时间监视它。哪个内存在增长,哪个不是? 不幸的是,无法根据给定的信息说什么。
答案 1 :(得分:0)
理论上,64位进程可以访问16 EB的虚拟内存,但是现代的CPU和OS通常会对此进行限制。 Windows允许寻址8 TB。请注意,无论计算机中有多少物理内存,所有64位进程都具有自己的专用8 TB虚拟内存块。 <unknown>
块指示通过虚拟分配(除其他外)使用的内存,其中包括.NET内存。这是您提到的1.835 GB虚拟内存。兆兆字节为1,024兆字节,仅占8兆字节总可寻址虚拟内存的很小一部分。结果,自由块仍然很大。这在64位程序中非常典型,因为很少有程序使用多个TB的内存。尝试使用32位程序进行此实验,以查看截然不同的结果。