写程序时,如果事先没有为崩溃情况留下后手。那么程序发布后,一旦发生崩溃。排查起来就十分麻烦了。我们只能对代码进行全面、仔细的推敲、分析。再加上bug的隐蔽性非常好,解决更是难上加难。下面我基于自己目前的认识,谈谈,如果提高排错的效率和解决问题的几率?我觉着以下的几个步骤,都是不可或缺的。
一、发布前
1、添加崩溃捕获的代码。
(1) 示例代码
// 处理Unhandled Exception的回调函数
LONG ApplicationCrashHandler(EXCEPTION_POINTERS *pException)
{
time_t t;
struct tm *local;
string AppPath;
char path[MAX_PATH] = { 0 };
t = time(NULL);
local = localtime(&t);
string dumfolder = Util::GetAppDirectory() + "dmp";
Util::CreateDirectoryW(dumfolder.c_str());
std::vector<std::string> files = Util::GetFolderFiles(dumfolder.c_str(), "*.*");
if (files.size() >= 10)
{
std::string DelFilePath = dumfolder + '\\' + files.front();
DeleteFileA(DelFilePath.c_str());
}
sprintf(path, "%s//%d%02d%02d%02d%02d%02d_sv.dmp", dumfolder.c_str(), 1900 + local->tm_year, local->tm_mon + 1, local->tm_mday, local->tm_hour, local->tm_min, local->tm_sec);
HANDLE hFile = ::CreateFileA(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
{
MINIDUMP_EXCEPTION_INFORMATION info;
info.ThreadId = GetCurrentThreadId();
info.ExceptionPointers = pException;
info.ClientPointers = TRUE;
::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hFile, MiniDumpWithFullMemory, &info, NULL, NULL);//MiniDumpNormal
CloseHandle(hFile);
}
return EXCEPTION_EXECUTE_HANDLER;
}
(2) 示例代码调用
SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)ApplicationCrashHandler);
2、log记录的信息足够详细。当崩溃dmp文件定位不到问题或定位的位置,不能有效地帮助我们确定问题所在的时候。
详细的log记录的重要性就突显出来了。
二、发布时
备份源代码和build出来的pdb文件。
三、崩溃排查
1、用vs2013打开备份的源程序。
2、将捕获的dmp文件,copy到发布程序的同级目录下。
3、vs2013打开程序后,会出现一个工作区,将dmp文件拖动工作区间中去。如下图所示:
4、在上图的界面中,停留片刻,界面显示。确认没什么有用信息后,点击右上角上的Debug with Native Only按钮,进入如下界面。
5、如果生成的pdb文件是由打开的程序编译而成,且dmp文件由编译后的可执行程序运行产生。上述的提示,可能是别的文字。一旦出现上述提示界面后,我们只要点击Yes,进入下一个显示界面。
6、出现上述界面后,点击一下Coninue按钮、再点击下Break按钮。进入下一个界面。
7、正常情况下,在红色方框中,就可以得到异常调用栈信息。通过这些信息,可以有效的帮助我们定位问题。如果和log结合起来进行协同分析,可能效果就更好了。