人无信不立/2008-04-26 22:30

Windbg入门:如何使用Windbg调试得到ArrayList的值

在.NET下开发时,最基本的调试方法就是使用Visual Studio的单步调试。但是对于一些特殊情况,特别是涉及到CLR内部的时候使用这种方式就达不到目的了。
如果要查看运行时内存使用情况,IL代码,CLR信息等可以使用以下两种方式:
1、使用VS2005 + sos.dll
2、使用Windbg + sos.dll
第二种方式功能更加强大,下面我就通过实际操作展示一下怎么使用这种方法得到运行时ArrayList内部的值。
有人可能会说:我直接用Visual Studio的单步调试岂不是更快?当然,这个只是一个演示,通过这个演示是为以后的高级调试打下基础

在操作之前,先熟悉一下基本知识:
A、使用VS2005 + sos.dll调试
1、需要在项目->属性->调试-〉启用非托管代码调试
2、打开调试-〉窗口-〉即时
3、在即时窗口中输入  !load sos 加载调试模块
4、输入其它调试语句

B、使用Windbg + sos.dll
1、去微软的网站下载最新的Windbg
2、打开Windbg在File-〉Symbol File Path ...窗口中输入 srv*c:\symbols*http://msdl.microsoft.com/download/symbols
3、运行需要调试的程序,然后在Windbg中File-〉Attach to Process中选择刚才运行的程序
4、在出现的Command窗口中就可以输入调试语句
5、常用调试语句:
 lm //查看加载了哪些模块
 .load C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\sos.dll  //加载调试模块
 ld TestClass //加载调试符号
 !name2ee TestClass.exe TestClass.Program.test  //显示test方法相关的地址
 !dumpmt -md 00976d48         //得到类的成员函数详细信息
 !dumpil 00973028    // 显示这个方法被编译器编译之后的IL代码
 !dumpheap -stat  //该命令显示程序中所有对象的统计信息,显示的大小是对象本身的大小,不包括对象里面值的大小
 !dumpheap -mt 790fcb30  //该命令显示MethodTable 790fcb30的详细信息
 !gcroot 012919b8  //来显示一个实例的所属关系
 !dumpobj(do) 012a3904 //显示一个对象的具体内容,看对象里面有什么,值是什么
 !ObjSize 012a1ba4 //对象实际在内存中的大小
 !eeheap -gc   //查看托管堆的情况(包括大小)
 !DumpArray   //查看数组信息

 下面就来看看具体的调试步骤:
1、我们的测试代码

namespace TestClass
{
    
class Program
    
{
        [STAThread]
        
static void Main(string[] args)
        
{
            ArrayList list 
= new ArrayList();
            list.Add(
"aaaa");
            list.Add(
"bbbb");
            Console.ReadLine();
        }

    }

}
很简单,就是一个ArrayList

运行这个程序(开始执行,不调试),然后进入Windbg,Attach到这个进程

2、查看所有堆栈信息
0:004> !dumpheap -stat
      MT    Count    TotalSize Class Name
7910062c        1           12 System.Security.Permissions.SecurityPermission
7918e284        1           16 System.IO.TextReader+SyncTextReader
79102d10        1           20 Microsoft.Win32.SafeHandles.SafeFileMappingHandle
79102cb4        1           20 Microsoft.Win32.SafeHandles.SafeViewOfFileHandle
79101d30        1           20 System.Text.InternalEncoderBestFitFallback
79100a7c        1           20 Microsoft.Win32.SafeHandles.SafeFileHandle
79105cd4        1           24 System.Collections.ArrayList
......
7912ad90       11         9036 System.Object[]
790fcb30     2083       131492 System.String
Total 2202 objects

除了我们的ArrayList外,还有很多其它的系统信息,先不用管它

3、查看我们的ArrayList的信息
0:004> !dumpheap -mt 79105cd4
 Address       MT     Size
012a1b88 79105cd4       24    
total 1 objects
Statistics:
      MT    Count    TotalSize Class Name
79105cd4        1           24 System.Collections.ArrayList
Total 1 objects


4、查看对应地址内部实际的值
0:004> !do 012a1b88
Name: System.Collections.ArrayList
MethodTable: 79105cd4
EEClass: 79105c28
Size: 24(0x18) bytes
 (C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
7912ad90  40008df        4      System.Object[]  0 instance 012a1bb0 _items
791018e0  40008e0        c         System.Int32  1 instance        2 _size
791018e0  40008e1       10         System.Int32  1 instance        2 _version
790fc35c  40008e2        8        System.Object  0 instance 00000000 _syncRoot
7912ad90  40008e3      1c0      System.Object[]  0   shared   static emptyArray
    >> Domain:Value  00149c58:012a1ba0 <<
可以看到ArrayList的大小为2,具体的值保存在地址012a1bb0中,是一个System.Object[]类型的数组

5、查看数组信息
0:004> !DumpArray 012a1bb0
Name: System.Object[]
MethodTable: 7912ad90
EEClass: 7912b304
Size: 32(0x20) bytes
Array: Rank 1, Number of elements 4, Type CLASS
Element Methodtable: 790fc35c
[0] 012a1b50
[1] 012a1b6c
[2] null
[3] null

6、查看数组内对象的值
0:004> !do 012a1b50
Name: System.String
MethodTable: 790fcb30
EEClass: 790fca90
Size: 26(0x1a) bytes
 (C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
String: aaaa
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
791018e0  4000096        4         System.Int32  1 instance        5 m_arrayLength
791018e0  4000097        8         System.Int32  1 instance        4 m_stringLength
790fe534  4000098        c          System.Char  1 instance       61 m_firstChar
790fcb30  4000099       10        System.String  0   shared   static Empty
    >> Domain:Value  00149c58:790d81bc <<
7912b1d8  400009a       14        System.Char[]  0   shared   static WhitespaceChars
    >> Domain:Value  00149c58:012a16f0 <<

这样我们就通过Windbg得到了ArrayList运行时的值了
posted @ 2007-12-29 17:28 永春 阅读(1829) 评论(13)  编辑 收藏 所属分类: .Net

  回复  引用  查看    
#1楼 2007-12-29 18:42 | 蛙蛙池塘      
!da -details
  回复  引用  查看    
#2楼 2007-12-29 18:52 | Justin      
  回复  引用  查看    
#3楼 [楼主]2007-12-29 18:54 | GSpring      
@Justin
好的,明年加入-_-,下班回家了
  回复  引用  查看    
#4楼 2007-12-29 19:13 | 蛙蛙池塘      
呵呵,都有小组啦。
  回复  引用  查看    
#5楼 2007-12-29 20:16 | 大石头      
可否请教一个问题,这几天都被这个问题搞疯了。

我的程序修改了一些东西后,打开页面时居然发现aspnet_wp.exe进程占了百分之九十左右的CPU,在页面完全打开以后,一直都是这样,在两台电脑上都是这样。不管是IIS还是VS自带的那个服务器,都是这样。

我的程序用了一年都没有碰到过这个问题。这一年来,增加了一些东西,比如缓存管理、日志输出、OLEDB线程池,这三个地方使用了Timer,但经过调试,好像不是它们的问题。最近为了增加授权功能,使用了很多WMI,还调用了一次Native API来去驱动器序列号,这个的确让程序慢了很多,但是好像也不是它造成了。

后来我用了很多手段,硬是找不到问题所在,请问有什么好方法么?
  回复  引用  查看    
#6楼 2007-12-29 20:43 | Jeffrey Zhao      
使用webdbg进行用户态调试还有一个重要的原因是产品环境下的调试,一是那里没有VS,二是产品环境的调试不允许停机,无法设置断点,三是有些问题是很难重现的,需要等着dump——当然这个示例还是设置端点了,呵呵。
  回复  引用    
#7楼 2007-12-29 21:49 | cf456 [未注册用户]
严重期待后文!
此文过于简单
  回复  引用  查看    
#8楼 2007-12-30 12:52 | 蛙蛙池塘      
@大石头
1、用Process/%Processor Time计数器找到耗费CPU最高的那个线程
2、用Thread/ID Thread计数器找到线程的win32 id
3、adplus -hang -p pid 抓Dump
4、~~[线程ID]e!clrstack -a查看那个线程在干什么,为什么耗费那么多CPU

@Jeffrey Zhao
确实是,后期维护的用windb和Wireshark机会很多。生产环境的排查就那么几种手段:计数器,trace,eventlog,dump,抓包,所以记trace,设计自定义计数器,协议设计的时候都得考虑到要对后期出问题的时候查问题有帮助才行。
比如在捕捉异常记error级trace的时候要把这个方法传入的参数或者可能会引起错误的变量记到trace里,要不看trace光知道出错了,没法排查。
  回复  引用    
#9楼 2007-12-31 06:38 | 又得登录? [未注册用户]
windbg针对managed code的反汇编结果是以native assembly形式显示还是msil形式显示?
如果是前者的话,冒似还得学习汇编语言才能用好这个东东。
  回复  引用  查看    
#10楼 2007-12-31 11:40 | 蛙蛙池塘      
@又得登录?
汇编是得懂一点
  回复  引用  查看    
#11楼 2007-12-31 22:34 | 钢钢      
不错,学习了 ^_^
  回复  引用  查看    
#12楼 [楼主]2008-01-02 08:45 | GSpring      
元旦回老家了,不能上网
多谢蛙蛙池塘的解答,高手呀
  回复  引用  查看    
#13楼 2008-01-02 17:13 | 大石头      
@蛙蛙池塘

我做到你说的第四步的时候,提示这个错误
No extension DLL name provided

是不是要预先加载sos?

标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      


相关链接: