多線程MT和多線程MD的區別

多線程MT加載的是靜態運行時庫,屬於C語言版本;而多線程MD版本加載是動態運行時庫,屬於微軟版本。在工程屬性窗體中選擇配置屬性,C++選項的代碼生成多線程調試 DLL (/MDd)和多線程調試 DLL (/MTd)是Debug版本,後面沒有d的是Release版本。

一、全局堆句柄不一樣。

網上有一個說法,就是一個線程一個棧,一個模塊一個堆。前者很容易有理解,每個線程創建的時候在CreateThread中都能制定默認棧大小,只是很多情況下都取了默認值。而一個模塊一個堆呢?其實很簡單測試,如果是一個多線程MT編譯方式的程序,你寫一個dll,導出一個函數,參數設置爲vector<int>,然後在exe中調用,當導出函數結束時就會崩潰掉。其實原因很簡單,就是因爲初始化向量空間時malloc內存的過程在exe中,而vector析構時會free內存,申請和釋放的模塊不一致而違背了一個模塊一個堆的說法。

細心者會發現,其實不管是new/delete還是malloc/free最終調用的都是HeapAlloc/HeapFree,而這個函數的第一個參數爲一個全局的堆句柄,由CreateHeap創建,創建該全局堆句柄的尚且在main等系列主函數之前。事實上這種誇模塊堆操作異常總結起來就是申請內存時HeapAlloc傳入的句柄和釋放該內存時HeapFree傳入的句柄不一致引起的,讀者可寫代碼測試。

但是以上問題如果是多線程MD編譯方式下便可解決,也就是說如果都是通過多線程MD編譯方式出來的程序,如果是A模塊中申請的內存到B模塊中釋放不會出現問題。

二、鏈接的運行時庫不同。

對於多線程MT的程序來說,其連接的是libcmt.lib,該文件屬於C語言運行時庫,整個lib都會連接到PE文件當中。而多線程MD的程序鏈接的卻是類似msvcpXXX.dll,該文件屬於微軟運行時庫.也就是說如果是多線程MD編譯出來的文件運行時都會加載相應版本的運行時庫,當如果找不到運行時庫就會報錯而無法運行,同時如果運行時庫不匹配也會出現各種意料之外的崩潰或者程序根本跑不起來等情況。

三、編譯出來的PE文件大小區別

此時如果兩者作爲對比就會很明顯看到多線程MT編譯出來的文件體積要比多線程MD編譯出來的大,因爲MT是把對應的運行時庫直接放到編譯出來的PE文件當中,而MD卻是運行的時候從第三方dll中獲取運行時庫,自己本身卻不包含。同時另外的區別也很明顯,多線程MT編譯出來的文件運行時不需要加載第三方dll所以運行效率要比多線程MD稍微高一點點,當然作爲用戶是完全感覺不到的。所以說如果打開一個程序目錄,發現裏面有類似msvcrtXX.dll,那麼這個程序幾乎可以肯定是用多線程MD方式編譯的。

四、總結說明

大多數軟件都是採用多線程MD方式編譯,例如QQ迅雷等等,如果找到他們目錄很容易發現上面提到的運行時庫。因爲這樣一來編譯出來的文件小,所有運行時庫統一,同時也讓內存管理簡單化,省去了跨模塊內存訪問帶來的各種bug。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章