到底是什么原因导致我的进程崩溃?
当你你有1000个w3wp.exe文件在eventviewer中意外停止,或者您的进程以某种奇怪的未定义方式退出,您不知道原因。
当一个进程崩溃或退出时,将触发一个称为EPR(Exit process)的特殊事件,因此使用类似于windbg.exe文件我们可以附加到进程中,等待epr被抛出,然后进行内存转储。安装windows调试工具时,会得到一个名为adplus的vbs脚本,它将为您自动执行此操作,并打印进程生命周期中发生的大多数异常的日志。
调试提示:当您在-crash模式下打开一个转储时,您将自动定位到崩溃发生时处于活动状态的线程(最有可能是可疑的线程)。如果您切换线程并想返回出错线程,请键入~列出所有线程,错误线程将被标记为一个点。
如果dump只显示进程中的一个活动线程,并且该线程是主线程,则该进程可能被外部的东西(运行状况监视、低系统内存、iisreset等)终止
不分先后顺序,以下是我们看到的支持率最高的一些:
Stack Overflow Exceptions
当为线程的堆栈分配的内存用完时,将发生堆栈溢出异常。默认情况下,它是1 MB,所以你的调用堆栈可能很深,所以大多数情况下发生这种情况是因为无限递归,也就是说,function调用FunctionB,后者再次调用FunctionB,后者再次调用FunctionB。。。没有停止条件。
不幸的是,异常处理应用程序块的错误使用是一个相当常见的模糊的无限递归情况。想象一下这个场景:你的应用程序得到一个异常,异常处理程序启动,你已经将它设置为记录到一个文件中。在记录日志时,您会得到某种类型的异常(比如访问被拒绝),并且您已经设置了异常处理程序来处理此异常。在这种情况下,您将在一个无限递归循环中处理一个异常,抛出另一个异常,处理它,抛出另一个。。。你明白要点了。这个故事的寓意是什么?不要在异常处理程序中使用异常处理程序来处理异常。
如果您运行“kb2000”(查看本机堆栈)和“!clrstack”(从sos.dll要查看托管堆栈),您可以找到递归模式以跟踪递归发生的位置/原因。
Out Of Memory Exceptions
大多数情况下,发生内存不足异常是由设计问题引起的,在设计问题中,缓存或会话作用域中存储的内存过多。如果以正确的方式使用缓存,那么缓存对于提高性能是非常有用的,也就是说,缓存的数据最多,而且缓存的时间不会超过需要的时间。在旧的ASP中,如果将对象存储在session范围内,就会出现问题,相信我,这是一种伪装,因为开发人员只在session范围内存储了最必要的项。例如,在会话范围内存储大型数据集通常会适得其反,因为您减少了网站可以处理的并发用户数,而且当内存足够大时,在缓存中进行垃圾收集和搜索所需的时间可能比从数据库中请求数据的开销要多真的需要它。
在何时应该在会话/缓存中存储内容以及何时不应该存储时,这里没有一刀切的解决方案。最好的做法是在早期阶段,确定应用程序需要能够处理的用户数,并在此基础上确定每个用户可以允许的存储量。然后对超过最大用户数的用户进行压力测试,以确保你能应付。最好是对处于会话状态的对象进行压力测试,看看性能如何。不同的用户数量不同。
在生产过程中,内存问题是很难解决的,因为它们通常需要大量的重新设计,所以在早期阶段花费一分钱可以节省很多钱。
调试提示:运行!dumpheap -type System.Web.Caching.Cache获取缓存根,然后对这些地址进行!do objsize,以了解您在缓存中为不同的应用程序存储了多少。(注意:InProc会话状态也存储在缓存中)
Unhandled exception in COM Component
当您因为堆损坏而崩溃时,出错的堆栈通常位于ntdll中的堆分配函数中,要解决此问题,您需要使用GFlags或PageHeap运行,以便能够当场抓到小偷。然而,之所以如此难以捕捉,是因为这些问题非常随机,很难重现。
如果发生崩溃,并且活动堆栈的顶部包含GC函数,则开始在代码中查找pinvoke,看看是否传递的缓冲区太小。
如果你的进程死了,同时你看到内存/available兆字节的大幅度下降,达到0,这可能会导致进程崩溃。当然,这里的任务是检查是什么进程偷走了内存。
External process kills/Recycles the process
无数次,当我有一个客户在崩溃模式下连接adplus时,我会发现内存转储,进程被外部的东西杀死了。我想添加这个问题,因为通常当你对崩溃进行故障排除时,这并不是你要排除的崩溃的真正原因(只有在极少数情况下),而是有人运行iisreset或者在不知道你有一个调试程序等待崩溃的情况下杀死了进程。所以如果你正在排除一个崩溃并得到一个内存转储。检查事件日志以确保没有人运行iisreset,因此这是导致崩溃转储的原因。这样可以节省你几个小时去寻找车祸的罪魁祸首。
另一个奇怪的地方是安装了某种监视软件来监视服务器是否按预期服务页面,如果没有,则关闭进程。但通常这也会在eventviewer中记录发生的事件。
Health monitoring settings
当然,我知道我们设置为每24小时循环一次进程,或者如果服务器空闲超过20分钟,但无论如何值得一提的是,因为我们经常遇到这些问题。同样,这里,通常会在事件日志中记录一个事件,说明进程被回收的原因,但故事的寓意是在iis或中简要查看应用程序池的运行状况监视设置计算机配置看看你打开了什么回收意见,这样你以后就不会有惊喜了。
发生崩溃的原因比上面提到的要多,但它们通常都是相当模糊的,所以我希望这篇文章能让你对如何开始寻找进程突然失效有一点了解。