一、常見故障介紹
最近在開發相機項目(項目細節由於公司保密就不介紹了),程序運行5個來月以來首次出現msvcr100.dll故障等問題,於是乎開始了分析之路,按照度娘上的一頓操作,期間也是出現了各種不一樣的問題,現總結了遇到的問題如:
1、MSVCR100.dll/MSVCR100D.dll/MSVCP100.dll/MSVCP100D.dll問題
問題事件名稱: APPCRASH
故障模塊名稱: MSVCR100.dll
2、R6010錯誤
現場遇到的情況基本都是這兩類
二、故障排查
1、靜心思考
主要說一下我走過的歷程,心酸只有自己知道,排查問題難免浮躁,但一定要沉得住,浮躁主要有以下幾點:
- 程序明明在自己機器上運行的好好的在客戶機器上就會出問題;
- 程序明明試着好好的,可你一離開就出現問題;
- 程序連續運行好幾個月版本都穩定了,可突然出問題,換電腦又復現不出來;
- 連續處理一段時間后仍然沒有結果,客戶領導天天催。
2、檢查庫
- 1、如果新打包的程序提示缺少MSVCR100.dll、MSVCP100.dll”或者“MSVCR100d.dll\MSVCP100d.dll”等類似錯誤信息,請從源機器或者網上下載該庫拷貝到目標機器,庫分32位和64位(跟自己操作系統有關),32拷貝到C:\Windows\System32,64位拷貝到C:\Windows\SysWOW64,記住庫一定要統一版本,不要從別的機器東拼西湊,以一個機器為准;
- 2、程序發布時最好將所需要的庫也一並打包,在這我以vs編譯器為例,可以從vs安裝目錄里拷貝MSVCR100.dll等相關運行庫,記得區分32或者64位版本,目錄如下:
- 3.如果以上兩步完成,程序重啟后,還會出現類似問題,則繼續往下排查,我給現場換完所有庫之后,出現了R6010問題引起程序宕機
3、排查代碼
1)、代碼層面檢查
以上若還沒解決問題,此時一定不要再糾結庫(不要以為庫版本不對),一定是你代碼的問題,檢查代碼着重檢查
- 1.非法指針訪問和內存泄漏
- 2.設置的指針范圍跟你運行的不對
- 3.指針訪問內存越界出現問題。
- 4.因為不支持中文。
- 5.內存不夠分配
- 6.多線程訪問資源出的問題。
- 7.檢查exe和dll是否混用的不同版本的crt
代碼檢查出異常更新版本后若問題解決皆大歡喜,若還沒有解決,請接着往下走(本人就屬於后者)。
2)、生成dump文件
一定要正視你的代碼,C++系統崩潰無非就是內存訪問無效、無效對象、堆棧溢出、空指針調用等常見的問題,當然有些問題不是立馬能復現,它需要一定的條件,而這個條件它很復雜又由許多因素所制約;
Dump文件是進程的內存鏡像。可以把程序的執行狀態通過調試器保存到dump文件中,Dump文件是用來給驅動程序編寫人員調試驅動程序用的,這種文件必須用專用工具軟件打開,比如使用WinDbg、VS打開,當程序崩潰時會生成dump文件,通過生成dump文件使用調試工具進行調試,還原程序崩潰時的狀態,能夠起到快速定位排查問題的作用,dump文件生成的方式如下:
(a)通過任務管理器生成
打開任務管理器,找到對應的進程,右擊,選擇創建轉儲文件
生成的文件路徑如下:
生成的轉儲文件可以通過VS打開,但是正常運行的程序生成.DMP文件並沒有什么大的作用,上述的方法要求在程序崩潰時並不直接退出時才可以使用,但是一般程序都是粗魯的退出,所以這種方法適用於特定場合。
(b)編寫代碼生成
一定要生成debug版本程序
Windows提供了SetUnhandledExceptionFilter函數,MSDN中描述為:
Issuing SetUnhandledExceptionFilter replaces the existing top-level exception filter for all existing and all future threads in the calling process.
用於當程序遇到未經處理的異常(主要指非指針造成)導致程序崩潰宕機時的異常接受處理,該函數必須在異常可能發生之前調用才有效,我們可以在該函數中生成dump文件,以方便我們調試,代碼網上很多,我貼出一部分(大佬不嫌棄請留言),在程序崩潰后會生成dump文件
1 int GenerateMiniDump(HANDLE hFile, PEXCEPTION_POINTERS pExceptionPointers, PWCHAR pwAppName) 2 { 3 BOOL bOwnDumpFile = FALSE; 4 HANDLE hDumpFile = hFile; 5 MINIDUMP_EXCEPTION_INFORMATION ExpParam; 6 7 typedef BOOL(WINAPI * MiniDumpWriteDumpT)( 8 HANDLE, 9 DWORD, 10 HANDLE, 11 MINIDUMP_TYPE, 12 PMINIDUMP_EXCEPTION_INFORMATION, 13 PMINIDUMP_USER_STREAM_INFORMATION, 14 PMINIDUMP_CALLBACK_INFORMATION 15 ); 16 17 MiniDumpWriteDumpT pfnMiniDumpWriteDump = NULL; 18 HMODULE hDbgHelp = LoadLibrary(L"DbgHelp.dll"); 19 if (hDbgHelp) 20 pfnMiniDumpWriteDump = (MiniDumpWriteDumpT)GetProcAddress(hDbgHelp, "MiniDumpWriteDump"); 21 22 if (pfnMiniDumpWriteDump) 23 { 24 if (hDumpFile == NULL || hDumpFile == INVALID_HANDLE_VALUE) 25 { 26 //TCHAR szPath[MAX_PATH] = { 0 }; 27 TCHAR szFileName[MAX_PATH] = { 0 }; 28 //TCHAR* szAppName = pwAppName; 29 TCHAR* szVersion = L"v1.0"; 30 TCHAR dwBufferSize = MAX_PATH; 31 SYSTEMTIME stLocalTime; 32 33 GetLocalTime(&stLocalTime); 34 //GetTempPath(dwBufferSize, szPath); 35 36 //wsprintf(szFileName, L"%s%s", szPath, szAppName); 37 CreateDirectory(szFileName, NULL); 38 39 wsprintf(szFileName, L"%s-%04d%02d%02d-%02d%02d%02d-%ld-%ld.dmp", 40 //szPath, szAppName, szVersion, 41 szVersion, 42 stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay, 43 stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond, 44 GetCurrentProcessId(), GetCurrentThreadId()); 45 hDumpFile = CreateFile(szFileName, GENERIC_READ | GENERIC_WRITE, 46 FILE_SHARE_WRITE | FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0); 47 48 bOwnDumpFile = TRUE; 49 OutputDebugString(szFileName); 50 } 51 52 if (hDumpFile != INVALID_HANDLE_VALUE) 53 { 54 ExpParam.ThreadId = GetCurrentThreadId(); 55 ExpParam.ExceptionPointers = pExceptionPointers; 56 ExpParam.ClientPointers = FALSE; 57 58 pfnMiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), 59 hDumpFile, MiniDumpWithDataSegs, (pExceptionPointers ? &ExpParam : NULL), NULL, NULL); 60 61 if (bOwnDumpFile) 62 CloseHandle(hDumpFile); 63 } 64 } 65 66 if (hDbgHelp != NULL) 67 FreeLibrary(hDbgHelp); 68 69 return EXCEPTION_EXECUTE_HANDLER; 70 } 71 72 73 LONG WINAPI ExceptionFilter(LPEXCEPTION_POINTERS lpExceptionInfo) 74 { 75 if (IsDebuggerPresent()) 76 { 77 return EXCEPTION_CONTINUE_SEARCH; 78 } 79 80 return GenerateMiniDump(NULL, lpExceptionInfo, L"test"); 81 }
(c)調試dump文件
終於在慢慢的等待中,現場程序崩潰,預期生成了dump文件,此時我們將dump文件拷貝到我們當時編譯的debug版本可執行程序的同級目錄下,注意pdb文件必須也在此目錄
用vs打開dmp文件並點擊使用僅限本機進行調試
出現異常時的彈窗即UnhandledExceptionFilter為默認的異常處理器工作產生的會出現中斷的提示框,此時點擊中斷
右下角會彈出堆棧信息
雙擊有問題的一行,會出現彈窗,再選擇代碼工程所在目錄(sln的目錄),即可定位到有問題的那一行
分析錯誤,加上異常保護,重新生成版本,問題解決,收工!