用一行代码让w3wp进程崩溃,如何查找w3wp进程崩溃的原因

W3wp进程崩溃了,在系统日志中留下了一个错误,而留下的错误信息却很少,如何才能快速查找w3wp崩溃的原因呢?

首先,我们来写一行代码让w3wp崩溃:

1
2
3
4
protected void Page_Load(object sender, EventArgs e)
{
    ThreadPool.QueueUserWorkItem(delegate(object noUse) { throw new Exception("go to hell w3wp!"); });
}

这一行代码就会让w3wp进程崩溃,因为asp.net 2.0之后,微软处理多线程操作异常的默认方式发生了变化,如果在Thread,或者ThreadPool,或者System.Threading.Timer中执行方法中出现未处理异常,则当前执行进程会停止执行崩溃。

 

当然实际情况中我们不会故意写这么一行代码让w3wp崩溃,也许你会说,我一般情况下不在web程序中使用Thread,或者ThreadPool,即便如此,出现崩溃也是有可能的,因为数据库的连接池,HttpRuntime管理请求队列等系统方法中也会用到Thread,或者System.Threading.Timer类,或者ThreadPool。我曾经亲身遭遇到系统方法导致崩溃,是因为sql server的数据库连接池被耗尽,取不出新的数据库连接而导致崩溃,这和以上一行代码导致崩溃的原理是一样的。

 

可以这么说这种崩溃是一种微软设计的应该崩溃的情况,微软认为如果在多线程中执行过程中发生异常就应该让进程崩溃。而这种崩溃发生之后留下的系统日志往往很少,我们只能看到崩溃的错误,而得不到崩溃的具体点或者崩溃发生的调用堆栈。俗话说:“办法总比苦难多”,虽然系统没有记录,但是我们可以通过代码来让系统记录崩溃原因。我们有两种办法来得到崩溃原因。

 

第一种办法是利用反射在Global的Application_End事件中记录HttpRuntime的退出堆栈和退出原因。如果你手头有反编译的工具,你可以反编译一下System.Web.HttpRuntime类,你可以看到此类有两个私有的字段:

1
2
private string _shutDownMessage;
private string _shutDownStack;

他们记录了w3wp进程的退出消息和退出堆栈,通常我们在Application_End事件中记录这两个变量的值,就可以看到崩溃的堆栈。具体怎么做请看代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
protected void Application_End(object sender, EventArgs e)
{
    HttpRuntime runtime = (HttpRuntime)typeof(System.Web.HttpRuntime).InvokeMember("_theRuntime",
        BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.GetField,
        null,
        null,
        null);
 
    if (runtime == null)
        return;
 
    string shutDownMessage = (string)runtime.GetType().InvokeMember("_shutDownMessage",
        BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField,
        null,
        runtime,
        null);
 
    string shutDownStack = (string)runtime.GetType().InvokeMember(
        "_shutDownStack",
        BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField,
        null,
        runtime,
        null);
 
    if (!EventLog.SourceExists(".NETRuntime"))
    {
 
        EventLog.CreateEventSource(".NETRuntime", "Application");
 
    }
 
    EventLog log = new EventLog();
 
    log.Source = ".NET Runtime";
 
    log.WriteEntry(String.Format("\r\n\r\n_shutDownMessage={0}\r\n\r\n_shutDownStack={1}", shutDownMessage, shutDownStack), EventLogEntryType.Error);
}

以上代码主要使用了反射,本文不做详细解释。

上面的这种方法通常情况可以得到w3wp崩溃的调用堆栈,我们还有另一种方法来获得。利用AppDomain.CurrentDomain.UnhandledException 事件来记录未处理异常的发生原因,代码也很简单:

1
2
3
4
5
6
7
8
9
10
11
protected void Application_Start(object sender, EventArgs e)
{
    AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
}
 
void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
    Exception ex = e.ExceptionObject as Exception;
    string msg = ex.Message;
    string stack = ex.StackTrace;
}

以上代码的是在Application Start的时候给AppDomain的UnhandleException时间加处理方法,来记录未处理异常的发生原因。

posted @   玉开  阅读(5516)  评论(17编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示