000000da`6bf0dbb0 000007fb`a0cbe7fd mscorwks!EESleepEx0x2d
000000da`6bf0dc30 000007fb`a1280769 mscorwks!Thread::UserSleep0x71
000000da`6bf0dc90 000007fb`415d09ee mscorwks!ThreadNative::Sleep0xf9
000000da`6bf0de40 000007fb`41630f39 App_Web_kng1ridv!ASP.sleep120_aspx.Page_Load(System.Object, System.EventArgs)0xe
…
000000da`6bf0f750 000007fb`a0d1970a mscorwks!UnManagedPerAppDomainTPCount::DispatchWorkItem0x157
000000da`6bf0f7f0 000007fb`a0dcf3a4 mscorwks!ThreadpoolMgr::WorkerThreadStart0x1ba
000000da`6bf0f890 000007fb`bc53167e mscorwks!Thread::intermediateThreadProc0x78
000000da`6bf0fae0 000007fb`beb53501 KERNEL32!BaseThreadInitThunk0x1a
000000da`6bf0fb10 00000000`00000000 ntdll!RtlUserThreadStart0x21
到此我们可以证明我们的想法了,原来ASP.NET启动了一个RequestTimeoutManager来负责查看超时线程,然后通过发送APC的方式打断超时线程使之抛出ThreadAbortException结束等待,最后ThreadAbortException被包装成HttpException抛出,记录在日志以及显示在客户端。requesttimedout
调试方法
现实过程中Timeout不一定是出程Sleep上,也不是所有的ThreadAbortException都代表Timeout的问题发生。我们还是要总结一下类问题的调试方法。
第一,观察timeout的时间,是否是100秒左右,与配置中的数是否相符(注意这里比一定是一秒不差,因为查看RequestTimeoutManager逻辑可以发现他是每隔15秒查看一下超时线程,所有存在15秒左右的误差。
第二,如果不是超时时间设置过小的原因,那就要通过抓dump的方式来查看具体的超时请求超时在什么操作上。因为我们最终得到的ThreadAbortException中没有调用栈信息。
如何抓到对的dump是个得研究的问题,我们可以把断点设在以下调用栈上的某个点上,注意断点越接近栈顶,这个方法可能被调用的次数就越多,抓到没有用的dump的可能性越大。
0:022> kL
Child-SP RetAddr Call Site
000000da`6bbfe808 000007fb`a10ce75b KERNEL32!QueueUserAPCStub
000000da`6bbfe810 000007fb`a0e37e88 mscorwks!Thread::Alert0xdb
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-36730-7.html
巴菲特哭了
除了垃圾米的垃圾脑残粉