2012-01-26 120 views
21

这是在x64机器上运行的.NET v4 Windows服务应用程序。在稳定运行几天之后的某个时刻,Windows服务内存的消耗像疯了似的疯狂直到崩溃。我能够以1.2 GB的速度捕获它并捕获内存转储。以下是我得到如何分析windbg中的<未分类>内存使用情况

如果我跑了!在WinDbg中解决-summary在我的转储文件,我得到后续结果

!解决-summary

--- Usage Summary ------ RgnCount ------- Total Size -------- %ofBusy %ofTotal 
Free      821  7ff`7e834000 ( 7.998 Tb)   99.98% 
<unclassified>   3696  0`6eece000 ( 1.733 Gb) 85.67% 0.02% 
Image     1851  0`0ea6f000 (234.434 Mb) 11.32% 0.00% 
Stack     1881  0`03968000 ( 57.406 Mb) 2.77% 0.00% 
TEB      628  0`004e8000 ( 4.906 Mb) 0.24% 0.00% 
NlsTables    1   0`00023000 (140.000 kb) 0.01% 0.00% 
ActivationContextData 3   0`00006000 ( 24.000 kb) 0.00% 0.00% 
CsrSharedMemory   1   0`00005000 ( 20.000 kb) 0.00% 0.00% 
PEB      1   0`00001000 ( 4.000 kb) 0.00% 0.00% 
- 
- 
- 
--- Type Summary (for busy) -- RgnCount ----- Total Size ----- %ofBusy %ofTotal 
MEM_PRIVATE      5837 0`7115a000 ( 1.767 Gb) 87.34% 0.02% 
MEM_IMAGE       2185 0`0f131000 (241.191 Mb) 11.64% 0.00% 
MEM_MAPPED       40 0`01531000 (21.191 Mb) 1.02% 0.00% 
- 
- 
--- State Summary ------------ RgnCount ------ Total Size ---- %ofBusy %ofTotal 
MEM_FREE       821 7ff`7e834000 ( 7.998 Tb)  99.98% 
MEM_COMMIT       6127 0`4fd5e000 ( 1.247 Gb) 61.66% 0.02% 
MEM_RESERVE      1935 0`31a5e000 (794.367 Mb) 38.34% 0.01% 
- 
- 
--Protect Summary(for commit)- RgnCount ------ Total Size --- %ofBusy %ofTotal 
PAGE_READWRITE      3412 0`3e862000 (1000.383 Mb) 48.29% 0.01% 
PAGE_EXECUTE_READ     220 0`0b12f000 (177.184 Mb) 8.55% 0.00% 
PAGE_READONLY      646 0`02fd0000 ( 47.813 Mb) 2.31% 0.00% 
PAGE_WRITECOPY      410 0`01781000 ( 23.504 Mb) 1.13% 0.00% 
PAGE_READWRITE|PAGE_GUARD   1224 0`012f2000 ( 18.945 Mb) 0.91% 0.00% 
PAGE_EXECUTE_READWRITE    144 0`007b9000 ( 7.723 Mb) 0.37% 0.00% 
PAGE_EXECUTE_WRITECOPY    70 0`001cd000 ( 1.801 Mb) 0.09% 0.00% 
PAGE_EXECUTE       1 0`00004000 ( 16.000 kb) 0.00% 0.00% 
- 
- 
--- Largest Region by Usage ----Base Address -------- Region Size ---------- 
Free       0`8fff0000  7fe`59050000 ( 7.994 Tb) 
<unclassified>     0`80d92000  0`0f25e000 (242.367 Mb) 
Image       fe`f6255000  0`0125a000 ( 18.352 Mb) 
Stack       0`014d0000  0`000fc000 (1008.000 kb) 
TEB        0`7ffde000  0`00002000 ( 8.000 kb) 
NlsTables      7ff`fffb0000  0`00023000 (140.000 kb) 
ActivationContextData   0`00030000  0`00004000 ( 16.000 kb) 
CsrSharedMemory     0`7efe0000  0`00005000 ( 20.000 kb) 
PEB        7ff`fffdd000  0`00001000 ( 4.000 kb) 

首先,为什么会非保密现身一次为1.73 GB,另一次为242 MB。第二,我明白,未分类可以意味着托管代码,但是我的堆大小根据!eeheap只有248 MB,它实际上匹配242,但不是接近于1.73GB。转储文件大小为1.2 GB,比正常情况高很多。我在哪里可以从这里了解什么是使用所有的记忆。托管堆世界中的任何内容都在248 MB以下,但我使用的是1.2 GB。

感谢

编辑

如果我这样做!堆-si得到以下

LFH Key     : 0x000000171fab7f20 
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: 00000000017e0000 - 00000000017e0000 (size 0000000000000000) 
Virtual block: 0000000045bd0000 - 0000000045bd0000 (size 0000000000000000) 
Virtual block: 000000006fff0000 - 000000006fff0000 (size 0000000000000000) 
0000000000060000 00000002 113024 102028 113024 27343 1542 11 3 1c LFH 
    External fragmentation 26 % (1542 free blocks) 
0000000000010000 00008000  64  4  64  1  1  1 0 0  
0000000000480000 00001002 3136 1380 3136  20  8  3 0 0 LFH 
0000000000640000 00041002  512  8 512  3  1  1 0 0  
0000000000800000 00001002 3136 1412 3136  15  7  3 0 0 LFH 
00000000009d0000 00001002 3136 1380 3136  19  7  3 0 0 LFH 
00000000008a0000 00041002  512  16 512  3  1  1 0 0  
0000000000630000 00001002 7232 3628 7232  18 53  4 0 0 LFH 
0000000000da0000 00041002 1536 856 1536  1  1  2 0 0 LFH 
0000000000ef0000 00041002 1536 944 1536  4 12  2 0 0 LFH 
00000000034b0000 00001002 1536 1452 1536  6 17  2 0 0 LFH 
00000000019c0000 00001002 3136 1396 3136  16  6  3 0 0 LFH 
0000000003be0000 00001002 1536 1072 1536  5  7  2 0 3 LFH 
0000000003dc0000 00011002  512 220 512 100 60  1 0 2  
0000000002520000 00001002  512  8 512  3  2  1 0 0  
0000000003b60000 00001002 339712 168996 339712 151494 976 116 0 18 LFH 
    External fragmentation 89 % (976 free blocks) 
    Virtual address fragmentation 50 % (116 uncommited ranges) 
0000000003f20000 00001002  64  8  64  3  1  1 0  0  
0000000003d90000 00001002  64  8  64  3  1  1 0  0  
0000000003ee0000 00001002  64  16  64  11  1  1 0  0  
------------------------------------------------------------------------------------- 
+0

使用SOS dll并查看堆的方式。由于这是一个.net程序,.NET框架所做的堆分配不会显示在非托管堆中。 – Zipper

+0

根据!eeheap(sos.dll),我的堆大小仅为248 MB。所以我不确定这是1.2 GB进程大小的原因,也不是1.7GB的原因,除非我错过了什么 – Mark

+0

你的服务是做什么的?您的服务是否包含非托管或C++/CLI代码?它看起来像一个非托管内存泄漏。 GDI,用户对象,句柄计数说什么?哪些调用堆栈被你的线程卡住? 〜* e!ClrStack和〜* e!DumpStack和〜* ekv是你的朋友,看看你的线程在做什么。一个线程正在分配内容? –

回答

2

“使用摘要”告诉你的非保密3696个区域产生总共17.33 Gb

“Largest Region”表示最大的未分类区域是242 Mb。 未分类(3695个地区)的其余部分一起使差异达到17.33 Gb。

尝试做一堆!-s并总结Virt col以查看本机堆的大小,我认为这些也落入了非托管存储区。 (NB早期版本显示来自!address -summary的本地堆栈)

+0

感谢您使用摘要vs最大区域的解释。我已经做了!堆-s和总结了美国山口,我得到359.12 MB。这是说什么吗?我已经添加了!堆的结果-s – Mark

+0

没有抱歉,因为这是一个64位转储,我没有实际经验。顺便说一下,哪个版本的.NET是从转储?这可能是其他可能知道更多的兴趣 –

+0

我已经将这些信息添加到他的问题描述中。它是.NET 4.0 – Mark

1

最好的办法是在windbg中使用EEHeap和GCHandles命令(http://msdn.microsoft.com/en-us/ library/bb190764.aspx),并尝试查看是否可以找到可能会漏出/错误的方式。

不幸的是,由于诊断这些类型的问题几乎总是非常耗时且在最简单的情况下需要有人做一个完整的事实,您可能无法获得您正在寻找的确切帮助分析转储。基本上,不太可能有人能够指引你直接回答堆栈溢出问题。大多数人可以指出你可能有用的命令。你将不得不做大量的挖掘工作,才能找到更多关于正在发生的事情的信息。

+0

指出正确的方向就足够了。就像我说的EEHeap似乎只描述了整个事情的248 MB,所以我不确定答案是否可以在那里。我会看看GCHandles – Mark

16

我最近有一个非常相似的情况,并发现一些在调查中有用的技术。没有什么是一颗银弹,但每个问题都有一点亮点。

1)来自SysInternals(http://technet.microsoft.com/en-us/sysinternals/dd535533)的vmmap.exe在关联本机和托管内存上的信息方面做得非常好,并在良好的用户界面中呈现它。使用下面的技术可以收集相同的信息,但这样更容易,也是一个很好的开始。可悲的是,它不适用于转储文件,您需要一个实时进程。

2)“!address -summary”输出是更详细的“!address”输出的汇总。我发现将详细输出放入Excel并运行一些支点很有用。使用这种技术,我发现被列为“”的大量字节实际上是MEM_IMAGE页面,可能是加载DLL时加载的数据页的副本,但在数据更改时复制。我也可以过滤到大的区域并钻入特定的地址。用牙签和大量祈祷在记忆中倾倒是痛苦的,但可以揭示。

3)最后,我做了一个穷人的版本的vmmap.exe技术上面。我加载了转储文件,打开了一个日志,并运行!address,!eeheap,!heap和!threads。我还将〜* k中列出的线程环境块与!teb对准。我关闭了日志文件并将其加载到我最喜欢的编辑器中。然后,我可以找到一个未分类的程序块,并搜索它是否从其中一个更详细的命令的输出中弹出。您可以快速关联本机堆栈和托管堆,以清除可疑未分类区域中的那些堆栈。

这些都是太手动。我很想编写一个脚本,它的输出与我在上面的技巧3中生成的输出类似,并输出适合查看vmmap.exe的mmp文件。有一天。

最后一个注意事项:我在vmmap.exe的输出和!地址输出之间做了一个关联,并注意到vmmap耦合了来自各种源(类似于堆!和!eeheap使用的地方)的这些类型,但是!地址不知道。也就是说,这些事情vmmap.exe标记,但报告没有!

.data 
.pdata 
.rdata 
.text 
64-bit thread stack 
Domain 1 
Domain 1 High Frequency Heap 
Domain 1 JIT Code Heap 
Domain 1 Low Frequency Heap 
Domain 1 Virtual Call Stub 
Domain 1 Virtual Call Stub Lookup Heap 
Domain 1 Virtual Call Stub Resolve Heap 
GC 
Large Object Heap 
Native heaps 
Thread Environment Blocks 

仍然有大量的“私有”字节下落不明,但同样,我能如果以缩小问题我可以除掉这些。

希望这给你一些关于如何调查的想法。我在同一条船上,所以我会很感激你找到的。谢谢!

+0

“我很想写一个脚本......查看vmmap”:你有机会这样做吗? –

1

我一直在调试工具的Windows 6.11.1.404副本这似乎是能够显示的东西“未分类”

与该版本更有意义,我看到TEB地址的列表,然后这个:

0:000> !address -summary 
--------- PEB fffde000 not found ---- 
TEB fffdd000 in range fffdb000 fffde000 
TEB fffda000 in range fffd8000 fffdb000 
...snip... 
TEB fe01c000 in range fe01a000 fe01d000 
ProcessParametrs 002c15e0 in range 002c0000 003c0000 
Environment 002c0810 in range 002c0000 003c0000 
-------------------- Usage SUMMARY -------------------------- 
    TotSize (  KB) Pct(Tots) Pct(Busy) Usage 
    41f08000 (1080352) : 25.76% 34.88% : RegionUsageIsVAD 
    42ecf000 (1096508) : 26.14% 00.00% : RegionUsageFree 
    5c21000 ( 94340) : 02.25% 03.05% : RegionUsageImage 
    c900000 ( 205824) : 04.91% 06.64% : RegionUsageStack 
      0 (  0) : 00.00% 00.00% : RegionUsageTeb 
    68cf8000 (1717216) : 40.94% 55.43% : RegionUsageHeap 
      0 (  0) : 00.00% 00.00% : RegionUsagePageHeap 
      0 (  0) : 00.00% 00.00% : RegionUsagePeb 
      0 (  0) : 00.00% 00.00% : RegionUsageProcessParametrs 
      0 (  0) : 00.00% 00.00% : RegionUsageEnvironmentBlock 
     Tot: ffff0000 (4194240 KB) Busy: bd121000 (3097732 KB) 

-------------------- Type SUMMARY -------------------------- 
    TotSize (  KB) Pct(Tots) Usage 
    42ecf000 (1096508) : 26.14% : <free> 
    5e6e000 ( 96696) : 02.31% : MEM_IMAGE 
    28ed000 ( 41908) : 01.00% : MEM_MAPPED 
    b49c6000 (2959128) : 70.55% : MEM_PRIVATE 

-------------------- State SUMMARY -------------------------- 
    TotSize (  KB) Pct(Tots) Usage 
    9b4d1000 (2544452) : 60.67% : MEM_COMMIT 
    42ecf000 (1096508) : 26.14% : MEM_FREE 
    21c50000 ( 553280) : 13.19% : MEM_RESERVE 

Largest free region: Base bc480000 - Size 38e10000 (931904 KB) 

与我的“当前”版本(6.12.2.633),我从同一个转储得到这个。我注意到两件事:

数据似乎是HeapAlloc/RegionUsageHeap和VirtualAlloc/RegionUsageIsVAD的总和)。

可爱的EFAIL错误,毫无疑问,部分原因是缺少数据!

我不知道如何来帮你托管代码,但我认为它实际上回答了原来的问题;-)

0:000> !address -summary 


Failed to map Heaps (error 80004005) 

--- Usage Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal 
<unclassified>       7171   aab21000 ( 2.667 Gb) 90.28% 66.68% 
Free         637   42ecf000 ( 1.046 Gb)   26.14% 
Stack         603   c900000 (201.000 Mb) 6.64% 4.91% 
Image         636   5c21000 ( 92.129 Mb) 3.05% 2.25% 
TEB          201    c9000 (804.000 kb) 0.03% 0.02% 
ActivationContextData     14    11000 ( 68.000 kb) 0.00% 0.00% 
CsrSharedMemory       1    5000 ( 20.000 kb) 0.00% 0.00% 

--- Type Summary (for busy) ------ RgnCount ----------- Total Size -------- %ofBusy %ofTotal 
MEM_PRIVATE       7921   b49c6000 ( 2.822 Gb) 95.53% 70.55% 
MEM_IMAGE        665   5e6e000 ( 94.430 Mb) 3.12% 2.31% 
MEM_MAPPED        40   28ed000 ( 40.926 Mb) 1.35% 1.00% 

--- State Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal 
MEM_COMMIT        5734   9b4d1000 ( 2.427 Gb) 82.14% 60.67% 
MEM_FREE        637   42ecf000 ( 1.046 Gb)   26.14% 
MEM_RESERVE       2892   21c50000 (540.313 Mb) 17.86% 13.19% 

--- Protect Summary (for commit) - RgnCount ----------- Total Size -------- %ofBusy %ofTotal 
PAGE_READWRITE       4805   942bd000 ( 2.315 Gb) 78.37% 57.88% 
PAGE_READONLY       215   3cbb000 ( 60.730 Mb) 2.01% 1.48% 
PAGE_EXECUTE_READ      78   2477000 ( 36.465 Mb) 1.21% 0.89% 
PAGE_WRITECOPY       74   75b000 ( 7.355 Mb) 0.24% 0.18% 
PAGE_READWRITE|PAGE_GUARD    402   3d6000 ( 3.836 Mb) 0.13% 0.09% 
PAGE_EXECUTE_READWRITE     80   3b0000 ( 3.688 Mb) 0.12% 0.09% 
PAGE_EXECUTE_WRITECOPY     80   201000 ( 2.004 Mb) 0.07% 0.05% 

--- Largest Region by Usage ----------- Base Address -------- Region Size ---------- 
<unclassified>        786000   17d9000 ( 23.848 Mb) 
Free          bc480000   38e10000 (910.063 Mb) 
Stack          6f90000    fd000 (1012.000 kb) 
Image          3c3c000   ebe000 ( 14.742 Mb) 
TEB           fdf8f000    1000 ( 4.000 kb) 
ActivationContextData       190000    4000 ( 16.000 kb) 
CsrSharedMemory        7efe0000    5000 ( 20.000 kb) 
0

最近我花了一些时间来诊断客户的问题,他们的应用程序在终止前使用了70GB(可能是由于遇到IIS应用程序池回收限制,但仍未确认)。他们给我发送了一个35 GB的内存转储。根据我最近的经验,以下是我可以对您提供的内容进行的一些观察:

在!堆-s输出中,“提交”列中显示了1.247 GB的284 MB。如果您要在DebugDiag中打开此转储,它会告诉您堆0x60000具有1 GB的提交内存。您将合计报告的11个细分的提交大小,并发现它们仅添加了大约102 MB而不是1GB。很烦人。

“丢失”的内存不会丢失。它实际上在!heap -s输出中暗示为“虚拟块:”行。 !遗憾的是,堆-s吸并没有正确显示的结束地址,因此报告的大小为0检查下列命令的输出:

!address 17e0000 
!address 45bd0000 
!address 6fff0000 

它会报告正确的结束地址,因此一个准确的“区域大小“。更好的是,它提供了一个简洁版本的区域大小。如果将这3个区域的大小添加到102 MB,则应该接近1 GB。

那么它们是什么?那么,你可以看看使用dq。通过深入探讨,你可能会发现他们被分配的原因。也许你的托管代码调用了一些本地方的第三方代码。

您可能会使用!heap 6fff0000 -x -v找到堆的引用。如果有参考文献,您可以通过再次使用!地址查看他们居住的存储区域。在我的客户问题中,我找到了一个生活在“Usage:Stack”区域的参考。一个“更多信息:”提示引用了堆栈的线程,它碰巧在顶部有一些大的basic_string追加/复制调用。

相关问题