如何通过 WinDBG 在 Dump 中查找非托管内存中的内容
How to find what is in unmanaged memory in Dump by WinDBG
I 运行 用于 WinDbg 命令中的转储文件
!地址-摘要
我的结果是这样的
Usage Summary RgnCount Total Size %ofBusy %ofTota
Free 3739 7ff5`dbbae000 ( 127.960 Tb) 99.97%
<unknown> 1677 5`680a1000 ( 21.626 Gb) 53.31% 0.02%
Heap 20349 4`0049f000 ( 16.005 Gb) 39.45% 0.01%
Stack 230 0`a3e90000 ( 2.561 Gb) 6.31% 0.00%
如何在堆中找到什么?什么是对象或什么是类型?
是Managed Heap,Heap是托管堆吗?
It is very hard to ask Questions Like this, so I added more info
这是我的 C# 示例代码
class Program
{
public static int[] arr;
public static AllocateUnmanagedMemory cls;
static void Main(string[] args)
{
const int GBSize = 1 * 1024 * 1024 * 1024/ sizeof(int);
Console.WriteLine("Allocating");
arr = new int[GBSize];
cls = new AllocateUnmanagedMemory();
cls.UnmanagedAllocation();
Console.ReadLine();
}
}
这是非托管分配代码:
使用系统;
使用 System.Runtime.InteropServices;
public class AllocateUnmanagedMemory
{
static IntPtr pointer;
public void UnmanagedAllocation()
{
pointer = Marshal.AllocHGlobal(1024 * 1024 * 1024 );
}
}
以及 Windows 10
中 WinDbg 预览版的结果
-- Usage Summary RgnCount ----------- Total Size -------- %ofBusy %ofTotal
Free 59 762f7000 ( 1.847 GB) 46.17%
<unknown> 98 4493e000 ( 1.072 GB) 49.76% 26.79%
Heap 15 40158000 ( 1.001 GB) 46.50% 25.03%
Image 174 2db2000 ( 45.695 MB) 2.07% 1.12%
MappedFile 15 1c51000 ( 28.316 MB) 1.28% 0.69%
Stack 24 800000 ( 8.000 MB) 0.36% 0.20%
我应该能找到一些用于非托管分配的代码,分配了 1Gb 内存。
基础知识
命令!address
在非常低的级别上运行,仅在操作系统之上。但是,它会识别 Windows 附带的一些内存管理器:Windows 堆管理器。
因此,您看到的 Heap
是通过 Windows 堆管理器分配的内存。以你的理解水平,那就是原生堆。
任何其他堆管理器将实现自己的内存管理。基本上它们的工作原理都是相似的:它们从 VirtualAlloc()
获取大块内存,然后尝试对该大块中的小块进行更好的管理。由于 WinDbg 不知道这些内存管理器中的任何一个,因此该内存被声明为 <unknown>
。它包括但不限于.NET 的托管堆。对于其他潜在用途,请参阅 。
Free
是可以从操作系统申请的内存。这可能包括交换 space,而不仅仅是物理 RAM。
Stack
,嗯,我认为这是显而易见的。
堆
How can I find what in in Heap? What are objects or what are types?
这个问题的答案在很大程度上取决于您所谈论的堆。
Windows 堆管理器(“本机堆”)只管理内存而不管理类型。在那个层面上区分两个大小相同但类型不同的对象是不可能的。如果你有内存泄漏,你只能给出“我有n个字节的泄漏”之类的声明。要查找有关本机堆的更多信息,请从 !heap -s
开始并查找其他 !heap
命令。
.NET 托管堆保留类型系统。要分析托管堆,您需要一个名为 sos 的 WinDbg 扩展。通常你通过 .loadby sos clr
加载它。它有一个命令 !dumpheap -stat
,这可能会让您对其功能有第一印象。 (运行 如果收到错误消息,则执行两次命令)
这应该会给您足够的提示来进行进一步的研究并在故障转储中找到更多详细信息。
St运行ge?
您似乎有 230 个堆栈,总共有 2.5 GB 的内存。每个堆栈大约有 11 MB 的内存。通常限制为 1 MB。
您更新的示例代码
我编译了下面的程序
using System;
using System.Runtime.InteropServices;
namespace SO55043889
{
class Program
{
public static int[] arr;
static IntPtr pointer;
static void Main()
{
const int GBSize = 1 * 1024 * 1024 * 1024/ sizeof(int);
Console.WriteLine("Allocating");
arr = new int[GBSize];
pointer = Marshal.AllocHGlobal(1024 * 1024 * 1024 );
Console.ReadLine();
Console.WriteLine(pointer.ToInt32() + arr[0]);
}
}
}
我 运行 应用程序和我使用 WinDbg 附加到进程。我使用
进行了转储
0:000> .dump /ma SO55043889.dmp
现在我们可以这样分析:
0:000> !address -summary
[...]
<unknown> 106 474f4000 ( 1.114 GB) 51.58% 27.86%
Heap 13 401e1000 ( 1.002 GB) 46.38% 25.05%
[...]
因此我们看到 1 GB(可能).NET 内存和 1 GB 本机内存。
0:000> .loadby sos clr
0:000> !dumpheap -stat
c0000005 Exception in C:\Windows\Microsoft.NET\Framework\v4.0.30319\sos.dumpheap debugger extension.
PC: 04f6fa73 VA: 00000000 R/W: 0 Parameter: 00000000
0:000> *** This is normal, just do it again
0:000> !dumpheap -stat
[...]
70d20958 12 1073742400 System.Int32[]
Total 335 objects
.NET 端有 12 个 int[],从托管堆中总共占用 ~1 GB。查看细节,我们看到只有一个大数组和一些较小的数组:
0:000> !dumpheap -type System.Int32[]
Address MT Size
020e1ff8 70d20958 300
020e2130 70d20958 24
020e2184 70d20958 40
020e2228 70d20958 80
020e2d9c 70d20958 16
020e2dac 70d20958 16
020e2df8 70d20958 16
020e386c 70d20958 24
020e3d54 70d20958 16
020e3d64 70d20958 16
020e3d74 70d20958 16
04811010 70d20958 1073741836
Statistics:
MT Count TotalSize Class Name
70d20958 12 1073742400 System.Int32[]
Total 12 objects
这不是您想知道的。我刚刚向您展示了在 .NET 方面它是多么容易。
现原生端:
0:004> !heap -s
LFH Key : 0x7f8d0cc6
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: 80010000 - 80010000 (size 00000000)
00550000 00000002 1024 504 1024 14 17 1 1 0 LFH
002d0000 00001002 64 16 64 2 2 1 0 0
00820000 00041002 256 4 256 2 1 1 0 0
00750000 00001002 64 20 64 7 2 1 0 0
00710000 00001002 256 4 256 0 1 1 0 0
001e0000 00041002 256 4 256 2 1 1 0 0
-----------------------------------------------------------------------------
我们在这里看不到 1 GB。这是有原因的。
如前所述,堆管理器擅长将 VirtualAlloc()
(64kB)中的大块分成较小的块。他们这样做是因为为 4 字节 int
分配 64kB 是一种很大的浪费。但是,没有必要为大块创建堆管理结构。对于 2^30+1 字节的分配,OS 将 return 2^30+64kB,这意味着开销仅为 0.006%。
这就是为什么您会发现 >512kB 的分配不是在通常的堆管理结构中而是作为 Virtual block
,这意味着 Windows 堆管理器只是将请求转发给 VirtualAlloc()
.
这里还有另一个问题:size
的输出已损坏。它说
(size 00000000)
这显然不是真的。我们自己看看:
0:004> !address 80010000
Usage: Heap
Base Address: 80010000
End Address: c0011000
Region Size: 40001000
[...]
0:004> ? c0011000-80010000
Evaluate expression: 1073745920 = 40001000
我们在这里看到的是 End Adress
- Base Address
等于 Region Size
并且大小为 1 GB。
在这一点上,值得注意的是用户模式堆栈跟踪数据库是无用的。它只适用于堆上的项目,而不适用于 VirtualAlloc()
。您不会弄清楚是谁分配了 1 GB 块。
而且我忘记启用用户模式堆栈跟踪数据库。让我们这样做并交叉检查
0:000> !gflag
Current NtGlobalFlag contents: 0x00001000
ust - Create user mode stack trace database
现在,小块内存应该有堆栈跟踪。在此示例中,我使用大小为 0x208 的任意块:
0:000> !heap -flt s 208
_HEAP @ 2a0000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
002c9818 0044 0000 [00] 002c9830 00208 - (busy)
002cd1e8 0044 0044 [00] 002cd200 00208 - (busy)
002d5ad0 0044 0044 [00] 002d5ae8 00208 - (busy)
002f0c48 0044 0044 [00] 002f0c60 00208 - (busy)
0032c210 0044 0044 [00] 0032c228 00208 - (busy)
00351c90 0044 0044 [00] 00351ca8 00208 - (busy)
0:000> *** Use any UserPtr number, I use the last one
0:000> !heap -p -a 00351ca8
address 00351ca8 found in
_HEAP @ 2a0000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
00351c90 0044 0000 [00] 00351ca8 00208 - (busy)
779dd909 ntdll!RtlAllocateHeap+0x00000274
71e18bc7 clr!EEHeapAlloc+0x0000002c
71e18c0a clr!EEHeapAllocInProcessHeap+0x0000005b
71e18ba6 clr!ClrAllocInProcessHeap+0x00000023
71e2dd26 clr!StackingAllocator::AllocNewBlockForBytes+0x00000082
71e2dd76 clr!operator new+0x00000063
71e93ace clr!MethodTableBuilder::BuildMethodTableThrowing+0x00000059
71e94590 clr!ClassLoader::CreateTypeHandleForTypeDefThrowing+0x0000083a
71e2e956 clr!ClassLoader::CreateTypeHandleForTypeKey+0x000000ad
71e2e99a clr!ClassLoader::DoIncrementalLoad+0x000000c2
71e2e418 clr!ClassLoader::LoadTypeHandleForTypeKey_Body+0x00000505
71e2e5a7 clr!ClassLoader::LoadTypeHandleForTypeKey+0x000000b5
71e2f723 clr!ClassLoader::LoadTypeDefThrowing+0x00000318
71e2a974 clr!ClassLoader::LoadTypeDefOrRefThrowing+0x0000024c
71f57811 clr!Assembly::GetEntryPoint+0x0000022f
71f856e0 clr!Assembly::ExecuteMainMethod+0x000000b3
71f855ed clr!SystemDomain::ExecuteMainMethod+0x00000631
71f858d3 clr!ExecuteEXE+0x0000004c
71f85819 clr!_CorExeMainInternal+0x000000dc
71f55a0c clr!_CorExeMain+0x0000004d
7251d93b mscoreei!_CorExeMain+0x0000010e
72597f16 MSCOREE!ShellShim__CorExeMain+0x00000099
72594de3 MSCOREE!_CorExeMain_Exported+0x00000008
77999802 ntdll!__RtlUserThreadStart+0x00000070
779997d5 ntdll!_RtlUserThreadStart+0x0000001b
请注意一点:如果您将程序修改为具有更小的内存块,例如
for (int i = 0; i < 1000; i++)
{
pointer = Marshal.AllocHGlobal(3*1024 );
}
您将看到堆中的分配:
0:004> ? 3*0n1024
Evaluate expression: 3072 = 00000c00
0:004> !heap -flt c00
cound not parse flt criteria -flt c00
0:004> !heap -flt s c00
_HEAP @ 67c0000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
0686b668 0183 0000 [00] 0686b680 00c00 - (busy)
0686efa8 0183 0183 [00] 0686efc0 00c00 - (busy)
[...]
你会看到堆栈跟踪
0:004> !heap -p -a 4d0fdf18
address 4d0fdf18 found in
_HEAP @ 67c0000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
4d0fdf00 0191 0000 [00] 4d0fdf18 00c00 - (busy)
779dd909 ntdll!RtlAllocateHeap+0x00000274
768f5aae KERNELBASE!LocalAlloc+0x0000005f
70c6ad4f mscorlib_ni+0x003fad4f
7138c4da mscorlib_ni+0x00b1c4da
71e0ebb6 clr!CallDescrWorkerInternal+0x00000034
71e11e10 clr!CallDescrWorkerWithHandler+0x0000006b
71e17994 clr!MethodDescCallSite::CallTargetWorker+0x0000016a
71f85026 clr!RunMain+0x000001ad
71f85707 clr!Assembly::ExecuteMainMethod+0x00000124
[...]
但是您不会看到托管方法调用。那是因为 USt 数据库是专为本机构建的。这与使用 k
或 !dumpstack
.
在 .NET 中使用不同堆栈的原因相同
I 运行 用于 WinDbg 命令中的转储文件
!地址-摘要
我的结果是这样的
Usage Summary RgnCount Total Size %ofBusy %ofTota
Free 3739 7ff5`dbbae000 ( 127.960 Tb) 99.97%
<unknown> 1677 5`680a1000 ( 21.626 Gb) 53.31% 0.02%
Heap 20349 4`0049f000 ( 16.005 Gb) 39.45% 0.01%
Stack 230 0`a3e90000 ( 2.561 Gb) 6.31% 0.00%
如何在堆中找到什么?什么是对象或什么是类型?
是Managed Heap,Heap是托管堆吗?
It is very hard to ask Questions Like this, so I added more info
这是我的 C# 示例代码
class Program
{
public static int[] arr;
public static AllocateUnmanagedMemory cls;
static void Main(string[] args)
{
const int GBSize = 1 * 1024 * 1024 * 1024/ sizeof(int);
Console.WriteLine("Allocating");
arr = new int[GBSize];
cls = new AllocateUnmanagedMemory();
cls.UnmanagedAllocation();
Console.ReadLine();
}
}
这是非托管分配代码:
使用系统; 使用 System.Runtime.InteropServices;
public class AllocateUnmanagedMemory {
static IntPtr pointer;
public void UnmanagedAllocation()
{
pointer = Marshal.AllocHGlobal(1024 * 1024 * 1024 );
}
}
以及 Windows 10
中 WinDbg 预览版的结果-- Usage Summary RgnCount ----------- Total Size -------- %ofBusy %ofTotal
Free 59 762f7000 ( 1.847 GB) 46.17%
<unknown> 98 4493e000 ( 1.072 GB) 49.76% 26.79%
Heap 15 40158000 ( 1.001 GB) 46.50% 25.03%
Image 174 2db2000 ( 45.695 MB) 2.07% 1.12%
MappedFile 15 1c51000 ( 28.316 MB) 1.28% 0.69%
Stack 24 800000 ( 8.000 MB) 0.36% 0.20%
我应该能找到一些用于非托管分配的代码,分配了 1Gb 内存。
基础知识
命令!address
在非常低的级别上运行,仅在操作系统之上。但是,它会识别 Windows 附带的一些内存管理器:Windows 堆管理器。
因此,您看到的 Heap
是通过 Windows 堆管理器分配的内存。以你的理解水平,那就是原生堆。
任何其他堆管理器将实现自己的内存管理。基本上它们的工作原理都是相似的:它们从 VirtualAlloc()
获取大块内存,然后尝试对该大块中的小块进行更好的管理。由于 WinDbg 不知道这些内存管理器中的任何一个,因此该内存被声明为 <unknown>
。它包括但不限于.NET 的托管堆。对于其他潜在用途,请参阅
Free
是可以从操作系统申请的内存。这可能包括交换 space,而不仅仅是物理 RAM。
Stack
,嗯,我认为这是显而易见的。
堆
How can I find what in in Heap? What are objects or what are types?
这个问题的答案在很大程度上取决于您所谈论的堆。
Windows 堆管理器(“本机堆”)只管理内存而不管理类型。在那个层面上区分两个大小相同但类型不同的对象是不可能的。如果你有内存泄漏,你只能给出“我有n个字节的泄漏”之类的声明。要查找有关本机堆的更多信息,请从 !heap -s
开始并查找其他 !heap
命令。
.NET 托管堆保留类型系统。要分析托管堆,您需要一个名为 sos 的 WinDbg 扩展。通常你通过 .loadby sos clr
加载它。它有一个命令 !dumpheap -stat
,这可能会让您对其功能有第一印象。 (运行 如果收到错误消息,则执行两次命令)
这应该会给您足够的提示来进行进一步的研究并在故障转储中找到更多详细信息。
St运行ge?
您似乎有 230 个堆栈,总共有 2.5 GB 的内存。每个堆栈大约有 11 MB 的内存。通常限制为 1 MB。
您更新的示例代码
我编译了下面的程序
using System;
using System.Runtime.InteropServices;
namespace SO55043889
{
class Program
{
public static int[] arr;
static IntPtr pointer;
static void Main()
{
const int GBSize = 1 * 1024 * 1024 * 1024/ sizeof(int);
Console.WriteLine("Allocating");
arr = new int[GBSize];
pointer = Marshal.AllocHGlobal(1024 * 1024 * 1024 );
Console.ReadLine();
Console.WriteLine(pointer.ToInt32() + arr[0]);
}
}
}
我 运行 应用程序和我使用 WinDbg 附加到进程。我使用
进行了转储0:000> .dump /ma SO55043889.dmp
现在我们可以这样分析:
0:000> !address -summary
[...]
<unknown> 106 474f4000 ( 1.114 GB) 51.58% 27.86%
Heap 13 401e1000 ( 1.002 GB) 46.38% 25.05%
[...]
因此我们看到 1 GB(可能).NET 内存和 1 GB 本机内存。
0:000> .loadby sos clr
0:000> !dumpheap -stat
c0000005 Exception in C:\Windows\Microsoft.NET\Framework\v4.0.30319\sos.dumpheap debugger extension.
PC: 04f6fa73 VA: 00000000 R/W: 0 Parameter: 00000000
0:000> *** This is normal, just do it again
0:000> !dumpheap -stat
[...]
70d20958 12 1073742400 System.Int32[]
Total 335 objects
.NET 端有 12 个 int[],从托管堆中总共占用 ~1 GB。查看细节,我们看到只有一个大数组和一些较小的数组:
0:000> !dumpheap -type System.Int32[]
Address MT Size
020e1ff8 70d20958 300
020e2130 70d20958 24
020e2184 70d20958 40
020e2228 70d20958 80
020e2d9c 70d20958 16
020e2dac 70d20958 16
020e2df8 70d20958 16
020e386c 70d20958 24
020e3d54 70d20958 16
020e3d64 70d20958 16
020e3d74 70d20958 16
04811010 70d20958 1073741836
Statistics:
MT Count TotalSize Class Name
70d20958 12 1073742400 System.Int32[]
Total 12 objects
这不是您想知道的。我刚刚向您展示了在 .NET 方面它是多么容易。
现原生端:
0:004> !heap -s
LFH Key : 0x7f8d0cc6
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: 80010000 - 80010000 (size 00000000)
00550000 00000002 1024 504 1024 14 17 1 1 0 LFH
002d0000 00001002 64 16 64 2 2 1 0 0
00820000 00041002 256 4 256 2 1 1 0 0
00750000 00001002 64 20 64 7 2 1 0 0
00710000 00001002 256 4 256 0 1 1 0 0
001e0000 00041002 256 4 256 2 1 1 0 0
-----------------------------------------------------------------------------
我们在这里看不到 1 GB。这是有原因的。
如前所述,堆管理器擅长将 VirtualAlloc()
(64kB)中的大块分成较小的块。他们这样做是因为为 4 字节 int
分配 64kB 是一种很大的浪费。但是,没有必要为大块创建堆管理结构。对于 2^30+1 字节的分配,OS 将 return 2^30+64kB,这意味着开销仅为 0.006%。
这就是为什么您会发现 >512kB 的分配不是在通常的堆管理结构中而是作为 Virtual block
,这意味着 Windows 堆管理器只是将请求转发给 VirtualAlloc()
.
这里还有另一个问题:size
的输出已损坏。它说
(size 00000000)
这显然不是真的。我们自己看看:
0:004> !address 80010000
Usage: Heap
Base Address: 80010000
End Address: c0011000
Region Size: 40001000
[...]
0:004> ? c0011000-80010000
Evaluate expression: 1073745920 = 40001000
我们在这里看到的是 End Adress
- Base Address
等于 Region Size
并且大小为 1 GB。
在这一点上,值得注意的是用户模式堆栈跟踪数据库是无用的。它只适用于堆上的项目,而不适用于 VirtualAlloc()
。您不会弄清楚是谁分配了 1 GB 块。
而且我忘记启用用户模式堆栈跟踪数据库。让我们这样做并交叉检查
0:000> !gflag
Current NtGlobalFlag contents: 0x00001000
ust - Create user mode stack trace database
现在,小块内存应该有堆栈跟踪。在此示例中,我使用大小为 0x208 的任意块:
0:000> !heap -flt s 208
_HEAP @ 2a0000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
002c9818 0044 0000 [00] 002c9830 00208 - (busy)
002cd1e8 0044 0044 [00] 002cd200 00208 - (busy)
002d5ad0 0044 0044 [00] 002d5ae8 00208 - (busy)
002f0c48 0044 0044 [00] 002f0c60 00208 - (busy)
0032c210 0044 0044 [00] 0032c228 00208 - (busy)
00351c90 0044 0044 [00] 00351ca8 00208 - (busy)
0:000> *** Use any UserPtr number, I use the last one
0:000> !heap -p -a 00351ca8
address 00351ca8 found in
_HEAP @ 2a0000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
00351c90 0044 0000 [00] 00351ca8 00208 - (busy)
779dd909 ntdll!RtlAllocateHeap+0x00000274
71e18bc7 clr!EEHeapAlloc+0x0000002c
71e18c0a clr!EEHeapAllocInProcessHeap+0x0000005b
71e18ba6 clr!ClrAllocInProcessHeap+0x00000023
71e2dd26 clr!StackingAllocator::AllocNewBlockForBytes+0x00000082
71e2dd76 clr!operator new+0x00000063
71e93ace clr!MethodTableBuilder::BuildMethodTableThrowing+0x00000059
71e94590 clr!ClassLoader::CreateTypeHandleForTypeDefThrowing+0x0000083a
71e2e956 clr!ClassLoader::CreateTypeHandleForTypeKey+0x000000ad
71e2e99a clr!ClassLoader::DoIncrementalLoad+0x000000c2
71e2e418 clr!ClassLoader::LoadTypeHandleForTypeKey_Body+0x00000505
71e2e5a7 clr!ClassLoader::LoadTypeHandleForTypeKey+0x000000b5
71e2f723 clr!ClassLoader::LoadTypeDefThrowing+0x00000318
71e2a974 clr!ClassLoader::LoadTypeDefOrRefThrowing+0x0000024c
71f57811 clr!Assembly::GetEntryPoint+0x0000022f
71f856e0 clr!Assembly::ExecuteMainMethod+0x000000b3
71f855ed clr!SystemDomain::ExecuteMainMethod+0x00000631
71f858d3 clr!ExecuteEXE+0x0000004c
71f85819 clr!_CorExeMainInternal+0x000000dc
71f55a0c clr!_CorExeMain+0x0000004d
7251d93b mscoreei!_CorExeMain+0x0000010e
72597f16 MSCOREE!ShellShim__CorExeMain+0x00000099
72594de3 MSCOREE!_CorExeMain_Exported+0x00000008
77999802 ntdll!__RtlUserThreadStart+0x00000070
779997d5 ntdll!_RtlUserThreadStart+0x0000001b
请注意一点:如果您将程序修改为具有更小的内存块,例如
for (int i = 0; i < 1000; i++)
{
pointer = Marshal.AllocHGlobal(3*1024 );
}
您将看到堆中的分配:
0:004> ? 3*0n1024
Evaluate expression: 3072 = 00000c00
0:004> !heap -flt c00
cound not parse flt criteria -flt c00
0:004> !heap -flt s c00
_HEAP @ 67c0000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
0686b668 0183 0000 [00] 0686b680 00c00 - (busy)
0686efa8 0183 0183 [00] 0686efc0 00c00 - (busy)
[...]
你会看到堆栈跟踪
0:004> !heap -p -a 4d0fdf18
address 4d0fdf18 found in
_HEAP @ 67c0000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
4d0fdf00 0191 0000 [00] 4d0fdf18 00c00 - (busy)
779dd909 ntdll!RtlAllocateHeap+0x00000274
768f5aae KERNELBASE!LocalAlloc+0x0000005f
70c6ad4f mscorlib_ni+0x003fad4f
7138c4da mscorlib_ni+0x00b1c4da
71e0ebb6 clr!CallDescrWorkerInternal+0x00000034
71e11e10 clr!CallDescrWorkerWithHandler+0x0000006b
71e17994 clr!MethodDescCallSite::CallTargetWorker+0x0000016a
71f85026 clr!RunMain+0x000001ad
71f85707 clr!Assembly::ExecuteMainMethod+0x00000124
[...]
但是您不会看到托管方法调用。那是因为 USt 数据库是专为本机构建的。这与使用 k
或 !dumpstack
.