服务器又崩溃了?看看专业的程序员怎么解决

首先让我为大家科普“崩了”是什么样子
 
01系统崩溃 
系统的崩溃主要发生在:程序未能注意到有东西出错、并继续运行 , 直到出现更严重的情况 。
 
例如试图“除以零” , 进而导致程序被迫中止 。
崩溃很可能在出现诱因后立刻发生 , 或等待很久后才发生 。
 
也有可能是错误信息导致的 , 但这类信息通常是由操作系统或应用程序框架显示 , 而非由程序代码本身显示 。
 
下图是一个典型的崩溃对话框:

服务器又崩溃了?看看专业的程序员怎么解决

文章插图
 
(应用 Sample.exe 崩溃后 windows 显示的错误信息)
这个错误信息是由 Windows 错误报告组件 WerFault.exe 显示的 。
 
为了确认这一点 , 可以将 Procexp 的十字准星图标拖拽到错误信息上 , 并查看拥有该窗口的进程 。
 
如下图显示了 Procexp 所展示的 , 故障的 Sample.exe 和 WerFault.exe 之间的关系 。
 
本例中 , Kernelbase.dll内的默认进程中崩溃处理代码使用 Sample.exe的PID作为一个命令行参数启动了 WerFault.exe(在Windows 8.1 中 , 崩溃处理代码还可对崩溃的进程创建不可执行的快照) 。
服务器又崩溃了?看看专业的程序员怎么解决

文章插图
 
(崩溃对话框是由 WerFault.exe 进程显示的)
 
02崩溃触发 
大部分崩溃均由无法处理的进程异常触发如果程序执行过程中遇到反常、不寻常 , 或非法的、无法由程序直接处理的情况 , 就会发生异常 。
 
随后将抛出有关具体状况以及遇到该状况的上下文信息 , 并将控制权转交给上一层异常处理程序 。
 
异常处理程序可以修复所遇到的状况 , 并将控制权返回给出现异常的位置;或立刻返回给出现异常时包含的区块;或由系统继续搜索能处理异常的处理程序 。
 
【服务器又崩溃了?看看专业的程序员怎么解决】如果找不到任何处理程序 , 则无法处理的异常会导致程序退出 。
 
03硬件异常和软件异常 
硬件异常:
CPU 检测到当前 CPU 指令违反某个规则而无法完成 。
最常见的部分例子包括:
 
1. 除以零;
2. 在 CPU 未处于特权模式(即 Ring 0) 的情况下执行特权指令;
3. 执行未定义的 Opcode , 如果 CPU 的指令指针设置为错误的内存地址就会发生这 种情况;
4. 访问未提交的虚拟内存;
5. 写入只读内存;执行被标记为不可执行(NX)的内存;以及栈溢出 。
 
软件异常:
与之相对的 , 如果程序检测到无法由自己直接处理的不寻常或错误状况 , 则此时会特意抛出软件异常 。
 
04定义专用的异常类 
C++和C#等语言的标准库定义和使用的类(Class)可以将不同类型异常的各种信息封装在一起 , 还使得程序员可以为自己的应用程序定义专用的异常类 。
例如.NET RegistryKey 类包含有关 Windows 注册表的访问操作 , 如果用户无权执行所请求的操纵 , 则将会抛出 SecurityException 。
 
程序员有责任了解自己的程序何时会抛出异常 , 并编写能妥善处理异常的代码 , 确保自己的程序不会崩溃 。
 
如果在抛出异常时 , 进程附加了 ProcDump 这样的调试器 , 那么调试器将先于其他所有异常处理程序获得通知 。
 
这个通知也叫做第一轮异常(First-chance exception) 。由于大部分第一轮异常最终都将由程序来处理 , 因此通常可忽略此类异常 。
 
如果没有异常处理程序可以处理这样的异常 , 那么调试器会再次收到 第二轮异常(Second-chance exception)的通知 , 这类异常也叫做未处理的异常(Unhandled exception) 。
 
05区别排查 
第一轮和第二轮异常的区别对排错工作很重要 。
 
例如应用程序可能由于开发者未能提供相应的异常处理 代码导致在遇到未处理的异常后崩溃 。
 
而附加的调试器可能根本没机会看到第二轮异常 , 因为应用程序 构建时所选择的目标平台已经在应用的外围提供了异常处理机制 , 在异常变为“未处理”状态并传递给 调试器之前就已接手了这个异常 。


推荐阅读