如何分析windbg </unclassified>中的<unclassified>内存使用情况

时间:2012-01-26 18:57:25

标签: debugging memory windbg unmanaged

这是在x64计算机上运行的.NET v4 Windows服务应用程序。在经过几天稳定运行后的某些时候,Windows服务内存消耗会像疯了一样飙升直到它崩溃。我能够以1.2 GB捕获它并捕获内存转储。这是我得到的

如果我在我的转储文件中的windbg中运行!address -summary,我会得到以下结果

!address -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。

由于

修改

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

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      
-------------------------------------------------------------------------------------

5 个答案:

答案 0 :(得分:16)

我最近遇到了类似的情况,并发现了一些在调查中有用的技巧。没有一个是银弹,但每个人都对这个问题有了更多的了解。

1)来自SysInternals的vmmap.exe(http://technet.microsoft.com/en-us/sysinternals/dd535533)可以很好地关联本机​​和托管内存的信息,并在一个漂亮的UI中呈现它。可以使用以下技术收集相同的信息,但这更容易,也是一个不错的起点。遗憾的是,它不适用于转储文件,您需要一个实时进程。

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

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

这些都是手动的。我喜欢编写一个脚本,其输出类似于我在上面的技术3中生成的输出,并输出适合查看vmmap.exe的mmp文件。有一天。

最后一点说明:我在vmmap.exe的输出与!地址输出之间进行了关联,并注意到vmmap夫妇从各种来源识别的这些类型的区域(类似于!heap和!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

仍然有很多“私人”字节下落不明,但同样,如果我可以将这些字段排除在外,我可以缩小这个问题。

希望这可以为您提供有关如何调查的一些想法。我在同一条船上所以我也很欣赏你所发现的东西。谢谢!

答案 1 :(得分:2)

“使用情况摘要”告诉您有3696个未分类区域,总计17.33 Gb

“最大区域”表示最大的未分类区域为242 Mb。 其余未分类(3695个区域)共同产生的差异高达17.33 Gb。

尝试做一个!heap -s并总结Virt col以查看原生堆的大小,我认为这些也属于非托管桶。   (NB早期版本显示本地堆显式来自!address -summary)

答案 2 :(得分:1)

你最好的选择是在windbg中使用EEHeap和GCHandles命令(http://msdn.microsoft.com/en-us/library/bb190764.aspx)并尝试查看是否可以找到这样泄漏/错误。

不幸的是,由于诊断这些类型的问题几乎总是非常耗时并且在最简单的情况之外需要有人进行全面分析,因此您可能无法得到您正在寻找的确切帮助。在转储上。基本上,不太可能有人能够指出你对Stack溢出的直接回答。大多数人都能够为您指出可能有用的命令。您将不得不进行大量挖掘以找到有关正在发生的事情的更多信息。

答案 3 :(得分: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)

答案 4 :(得分:0)

我最近花了一些时间来诊断他们的应用程序在终止之前使用70GB的客户问题(可能是因为达到了IIS应用程序池回收限制,但仍然未经证实)。他们给了我一个35 GB的内存转储。根据我最近的经验,这里有一些关于你提供的内容的观察结果:

在!heap -s输出中,提交列中显示了284 MB的1.247 GB。如果您要在DebugDiag中打开此转储,它会告诉您堆0x60000具有1 GB的已提交内存。您将累计报告的11个段的提交大小,并发现它们只加起来大约102 MB而不是1GB。太烦人了。

缺少“缺失”记忆。它实际上在!heap -s输出中暗示为“Virtual block:”行。不幸的是,!heap -s糟透了,并没有正确显示结束地址,因此报告大小为0.检查以下命令的输出:

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

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

那么它们里面有什么?好吧,你可以看看使用dq。通过洞察你可能会发现他们被分配的原因。也许您的托管代码会调用一些具有本机端的第三方代码。

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