我是Windbg的新手,并尝试了解有关值和引用类型.NET的一些内容。这是我正在使用的代码
class Program
{
struct MyStruct
{
int x;
int y;
}
class MyClass
{
int x;
int y;
}
static void Main(string[] args)
{
MyStruct s ;
MyClass c = new MyClass();
Thread.Sleep(5 * 60 * 1000);
}
}
我在这里睡觉的唯一原因是让我有时间将Windbg附加到正在运行的进程中。我知道一个更好的方法可能是设置一个断点,但无论如何这里都是我的问题。
0:003> !threads -special
ThreadCount:2
UnstartedThread:0
BackgroundThread:1
PendingThread:0
DeadThread:0
托管运行时:没有
PreEmptive Lock
ID OSID ThreadOBJ状态GC GC分配上下文域计数APT异常
0 1 bbc 0000000000190c50 200a020已启用00000000027f3ca8:00000000027f3fd0 0000000000187e40 0 MTA
2 2 106c 0000000000198430 b220已启用0000000000000000:0000000000000000 0000000000187e40 0 MTA(终结器)
OSID特殊螺纹类型
1 e98 DbgHelper
2 106c Finalizer
0:003> !CLRStack
操作系统线程ID:0xe6c(3)
无法遍历托管堆栈。目前的线程可能不是一个
托管线程。您可以运行!threads来获取中的托管线程列表
过程中
0:003> KB
RetAddr:Args to Child:呼叫站点
00000000 77978778 : 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 : ntdll!DbgBreakPoint
776d466d:00000000
0000000000000000 00000000
00000000 00000000 00000000 00000000
00000000:ntdll!DbgUiRemoteBreakin + 0x38
00000000 778d8791 : 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 : KERNEL32!BaseThreadInitThunk+0xd
00000000:00000000
0000000000000000 00000000
00000000 00000000 00000000 00000000
00000000:ntdll!RtlUserThreadStart + 0x1d
0:000> !CLRStack
操作系统线程ID:0xbbc(0)
Child-SP RetAddr呼叫站点
000000000031edb0 000007fef6b32012 ConsoleApplication2.Program.Main(System.String [])
0:000> !DumpStackObjects
操作系统线程ID:0xbbc(0)
RSP / REG对象名称
000000000031edd8 00000000027f3c90 ConsoleApplication2.Program + MyClass
000000000031ede8 00000000027f3c90 ConsoleApplication2.Program + MyClass
000000000031ee00 00000000027f3c70 System.Object [](System.String [])
000000000031ef88 00000000027f3c70 System.Object [](System.String [])
000000000031f170 00000000027f3c70 System.Object [](System.String [])
000000000031f198 00000000027f3c70 System.Object [](System.String [])
TIA
答案 0 :(得分:3)
当您附加到正在运行的进程时,调试器会将一个线程注入进程,并将其作为当前线程选择。正如Liran所指出的那样,SOS命令!threads
仅列出了托管线程。
对于一个简单的控制台应用程序,您应该会看到两个托管线程;运行应用程序的主线程和由CLR启动的终结器线程。根据我的经验,他们总是分别编号为0和2。
!dso
命令显示堆栈上的引用。它不列出值类型。为此,您可以将!clrstack
命令与-l
一起用于本地人。请记住,这些很少会被放置在堆栈上以获得优化的代码,而在x64上,调用约定使得跟踪它们变得更加困难。
答案 1 :(得分:1)
!Threads
命令仅显示托管线程(它将丢弃纯粹的本机线程)
要查看所有线程(都是托管非托管),您可以使用~
。 (您可以使用诸如~*kb
之类的命令转储本机堆栈[其中*
表示“对于每个线程”]。)
!dso
命令仅显示引用类型,有时它可能显示“误报”或只是错误的数据(您会发现SOS有点buggy nature)。
从SOS的帮助(!help
):
!DumpStackObjects [-verify] [顶部堆栈 [底部堆栈]]
此命令将显示任何托管 它在范围内找到的对象 当前的堆栈。结合 堆栈跟踪命令,如K和 !CLRStack,这是一个很好的帮助 确定当地人的价值观 参数。
如果您使用-verify选项,则每个 对象的非静态CLASS字段 候选人经过验证。这有助于 消除误报。它不是 在默认情况下,因为经常在一个 调试方案,你是 对无效的对象感兴趣 字段。
缩写!dso可用于 简洁。