寫代碼也已經有4年了,其實自己每天都在進步,最近經常看技術總監調試,看他操作電腦,調試 bug,自己學習到很多東西。他也願意帶我,幾次遇到問題,都跑到我機子上調試問題。但是大牛們,都不可能事無巨細地詳述這些技能的,他只會教會你一個思路,一個方法,讓你自己去百度,去Google,去跟其他大師交流,去自己領悟。最近產品運營的確出現不少問題,基本上是在不停的 debug 中讓服務端穩定下來,現在使用者都很苛刻的了,很多霸王條款,服務程式 down 了,要賠錢的,老闆著緊,自己壓力也不少啊。一切都得為穩定而奮力。最近接觸了 windbg,對這個東西高度興趣,當然現在也還很菜,感覺自己進步了,能夠促進整個團隊的效率,讓大家都能受益。
《軟體調試》 這本書是去年一月份買的,看了一段時間,感覺看不懂,現在回頭再拿過來翻,感覺沒那麼吃力了,因為現在看懂了,可以馬上用在產品上,心裏面有種莫名的興奮,張老師確實是位大師,與大師交流,受益良多。這本書之前翻看了很多的章節,也是為了以後便於記憶,寫下劄記。
1、頓悟
運行庫和運行期檢查,這個東西以前 VC6 下接觸這個東西很多,知道有時候 CString 或者一些記憶體莫名其妙的釋放報錯,有可能是運行期庫出現問題,倒騰一下就好了,但知其然而不知其所以然,最近一個同事出現這個問題,我忽然想到這個,忽然就明白了是怎麼一回事,可能這就是頓悟吧,感覺很奇妙的。後來看張老師的文字,自己又有了更系統的認識了。
2、C/C++ 運行庫
當編譯器在將進階語言編譯到低級語言的過程中時,因為進階語言中的某些比較複雜的運算子要對應比較多的低級語言指令,為了防止這樣的指令段多次重複出現在目標代碼中,編譯器通常將這些指令段封裝為函數,然後將進階語言的某些操作翻譯為函數調用。(比如 new 和 delete 操作符編譯為對 malloc 和 free 函數的調用)
所以我以前一直望文生義,以為 new 和 delete 就一定是 C++ 的記憶體處理,它的底層很可能是封裝了 malloc 和 free, 所以有時候 dll 裡申請的記憶體,跑到 exe 裡釋放,或者相反,這樣都可能產生不可預料的問題。
3、連結運行庫
VC6 編譯器的 C 運行庫 DLL 支援庫 release 的是 MSVCRT.DLL,調試版的是 MSVCRTD.DLL
VC6 編譯器的 C++ 運行庫 DLL 支援庫 release 的是 MSVCRT60.DLL,調試版的是 MSVCRT60D.DLL
4、多個運行庫執行個體
對於靜態連結運行庫的程式模組,不論事 EXE還是DLL,每個模組的內部都複製了一份運行庫的變數和代碼(部分)。也就是說每個模組中都有一個運行庫的執行個體。當進程中有多個運行庫執行個體時,每個運行庫執行個體會各自使用自己的資料(變數)和資源(堆),理論上是可以正常工作的,但有時也可能引發問題,其中之一就是從一個 CRT 堆分配的記憶體被送給另一個 CRT 執行個體來釋放,在調試版本中,CRT 的記憶體檢查功能會發現這一個問題並報告錯誤,但再發布版本中,便會導致嚴重的問題。
5、EXE 模組的入口函數一覽
使用者入口函數 CRT入口函數 應用
main mainCRTStartup 控制台程式
wmain wmainCRTStartup 寬字元的控制台程式
WinMain WinMainCRTStartup Win32應用程式
wWinMain wWinMainCRTStartup 寬字元的Win32應用程式
DLL 的模組使用者入口函數是 DLLMain,因為 DLLMain 沒有字元類型的參數,所以對於寬字元的 DLL 模組,其入口函數也是 DLLMain
BOOL WINAPI DLLMain(HANDLE hDllhandle, /*模組控制代碼,即基地址*/, DWORD dwReason /*調用原因*/, LPVOID lpreserved);
(很多時候我們都是從 main 開始編碼的,而 main 的前後的工作卻不大瞭解,以前看過《windows 核心編程》裡面好像也有說)