.NET调试实例-实验1:死锁 (原创翻译)

-原文地址:http://blogs.msdn.com/tess/archive/2008/02/04/net-debugging-demos-lab-1-hang.aspx
译者注释 (Just do it)    在这篇文章里,Tess精心为我们准备了一堂需要很强动手能力的实验课,“授人以鱼不如授人以渔”,她真的是用心良苦!所以希望读者们不要急于去问答案是什么,实验平台已经搭好了,让我们一起去探索吧!欢迎大家在留言栏里对实践结果进行讨论!
1、首先,作者详细介绍了如何重现问题,即如何培养一只小白鼠。
2、其次,作者简单介绍了如何获取Dump。
3、再次,作者在此基础上提出了若干问题(Q),一步步启发读者去靠自己的实践和思考定位和解决问题。
4、最后,作者给出了几篇跟死锁有关的文章索引,供读者在实践的时候参考。

//先给大家一点提示:参考:http://msdn.microsoft.com/en-us/library/ms173179.aspx
lock (x)
{
    DoSomething();
}


This is equivalent to:

System.Object obj 
= (System.Object)x;
System.Threading.Monitor.Enter(obj);
try
{
    DoSomething();
}

finally
{
    System.Threading.Monitor.Exit(obj);
}
希望大家能真正亲自动手实践,然后踊跃留言啊!

这是关于.NET调试的10个实验里的第一个。这个实验的对象是个名叫BuggyBits的站点,就像名字暗示的一样,虫子的攻击是非常凶猛地!(buggy:多虫的, 臭虫成灾的)

开始前,请务必按照前面的安装说明做好准备工作。

我想大家在动手实践的时候可能会遇到很多问题,尽管我会尽可能地多回答留言栏里的问题,但是我不能保证回答所有的问题,所以请大家遇到你们能解答的问题的时候,请尽可能地直言相告。这里还要强调一下,请确保你已经严格遵守了所有的安装说明。

注意:实验中的问题(Q: …)只是定位解决问题时可能会用到的帮助信息。在我发布对应的实验回顾(为了给大家一段没有答案的时间思考,实验回顾大约在原实验发布一周后发布)之前,我将适当地控制一些包含答案的评论。

请大家在评论里畅所欲言,无论好与坏,这样我才能知道在未来的实验里做那些改进。

不多说了,现在我们开始实验1:

重现问题:

1.浏览 http://localhost/BuggyBits/FeaturedProducts.aspx 这个页面将延时5秒显示,你能在页面底部看到开始时间和执行时间。

2.打开5个以上的浏览器同时浏览这个页面,并且同时刷新。

注意每一个页面的执行时间并确保它们的开始时间几乎都完全一样。(如果开始时间不同,你有可能是没有执行那个reg文件)

Q:执行时间怎么样?

Q:问题重现的时候,w3wp.exe进程的CPU利用率怎么样?高还是低?

Q:出现死锁症状的潜在原因是什么?


获取内存转储文件:

1.打开一个命令行窗口,然后进入到你的调试器工具集目录。输入下面的命令行准备获取转储文件,但是暂时先不要执行。

adplus –hang –pn w3wp.exe –quiet

2.重现问题,使用刚才同时刷新5个浏览器的方法或者通过下面的命令行使用tinyget给那个网页施压的方法。

tinyget -srv:localhost -uri:/BuggyBits/FeaturedProducts.aspx -threads:30 -loop:50


3.在刚才的adplus窗口敲回车就可以在所有请求正在执行的时候获得内存转储文件。

Q:adplus处于挂起模式的时候,什么触发了生成内存转储文件?

Q:你需要有什么样的权限才可以获取到一个进程的内存转储文件?

Q:转储文件被创建在那里? 提示:查阅一下Windbg的帮助文件,关于adplus/挂起模式部分。


使用windbg.exe打开转储文件

1.启动Windbg,使用"File/Open Crash dump"菜单打开刚才获得的内存转储文件。

2.设置符号文件的路径 (具体参考:信息和安装说明)

3.加载SOS (具体参考:信息和安装说明)

检查堆栈

1.检查本地调用堆栈

~* kb 2000

2.检查.NET调用堆栈

~* e !clrstack

Q:你是否发现了一些某个线程正在等待其它同步机制的典型迹象或者在调用堆栈上看出某些可能性?

定位并解决死锁

1.确定持有锁的线程的ID.

!syncblk

Q:什么线程拥有锁?

Q:有多少线程在等待解锁?

提示:MonitorHeld = 1时表示这个线程持有锁,MonitorHeld = 2时表示这个线程被阻塞!

2.挑选一个堵塞线程(提示:堵塞线程位于AwareLock::Enter),看看它在做什么?

    ~5s              (切换到线程5)
    kb 2000         (检查本地堆栈)
    !clrstack        (检查.NET堆栈)


Q:堵塞线程等待的锁在那个.NET函数里?

3.检查持有锁的线程在做什么?

    ~5s             (切换到线程5)
    kb 2000        (检查本地堆栈)
    !clrstack       (检查.NET堆栈)

Q:为什么会发生死锁?

4.检查代码,看是否有方法使用了锁,进一步证明你的假设。

提示

下面的文章在定位和解决这个死锁问题的时候可能会用到:

Things to ignore when debugging an ASP.NET Hang - Update for .NET 2.0

A Hang Scenario, Locks and Critical Sections

.NET Hang Debugging Walkthrough

Automated .NET Hang Analysis

Debug 探索团队
-博客园.Debug探索团队
-By Justin/2008年7月8日 21:07:32

posted @ 2008-07-08 21:31 Justin 阅读(...) 评论(...) 编辑 收藏