這段時(shí)間司在招實(shí)習(xí)生,而不管是遠(yuǎn)程的電話面試或者是實(shí)際現(xiàn)場面試中領(lǐng)導(dǎo)都喜歡問你這個(gè)問題,但是可惜的是能很好答上來的人很少。后來發(fā)現(xiàn)不管是應(yīng)屆的實(shí)習(xí)生,甚至有些實(shí)際參加工作幾年的人也未必真的了解這個(gè)問題。今天想寫一篇詳解,希望對(duì)廣大程序員有一定的幫助。 區(qū)別1:全局堆句柄不一樣。 網(wǎng)上有一個(gè)說法,就是一個(gè)線程一個(gè)棧,一個(gè)模塊一個(gè)堆。前者很容易有理解,每個(gè)線程創(chuàng)建的時(shí)候在CreateThread中都能制定默認(rèn)棧大小,只是很多情況下都取了默認(rèn)值。而一個(gè)模塊一個(gè)堆呢?其實(shí)很簡單測試,如果是一個(gè)多線程MT編譯方式的程序,你寫一個(gè)dll,導(dǎo)出一個(gè)函數(shù),參數(shù)設(shè)置為vector<int>,然后在exe中調(diào)用,當(dāng)導(dǎo)出函數(shù)結(jié)束時(shí)就會(huì)崩潰掉。其實(shí)原因很簡單,就是因?yàn)槌跏蓟蛄靠臻g時(shí)malloc內(nèi)存的過程在exe中,而vector析構(gòu)時(shí)會(huì)free內(nèi)存,申請(qǐng)和釋放的模塊不一致而違背了一個(gè)模塊一個(gè)堆的說法。 細(xì)心者會(huì)發(fā)現(xiàn),其實(shí)不管是new/delete還是malloc/free最終調(diào)用的都是HeapAlloc/HeapFree,而這個(gè)函數(shù)的第一個(gè)參數(shù)為一個(gè)全局的堆句柄,由CreateHeap創(chuàng)建,創(chuàng)建該全局堆句柄的尚且在main等系列主函數(shù)之前。事實(shí)上這種夸模塊堆操作異??偨Y(jié)起來就是申請(qǐng)內(nèi)存時(shí)HeapAlloc傳入的句柄和釋放該內(nèi)存時(shí)HeapFree傳入的句柄不一致引起的,讀者可寫代碼測試。 但是以上問題如果是多線程MD編譯方式下便可解決,也就是說如果都是通過多線程MD編譯方式出來的程序,如果是A模塊中申請(qǐng)的內(nèi)存到B模塊中釋放不會(huì)出現(xiàn)問題。 區(qū)別2:鏈接的運(yùn)行時(shí)庫不同。 對(duì)于多線程MT的程序來說,其連接的是libcmt.lib,該文件屬于C語言運(yùn)行時(shí)庫,整個(gè)lib都會(huì)連接到PE文件當(dāng)中。而多線程MD的程序鏈接的卻是類似msvcpXXX.dll,該文件屬于微軟運(yùn)行時(shí)庫.也就是說如果是多線程MD編譯出來的文件運(yùn)行時(shí)都會(huì)加載相應(yīng)版本的運(yùn)行時(shí)庫,當(dāng)如果找不到運(yùn)行時(shí)庫就會(huì)報(bào)錯(cuò)而無法運(yùn)行,同時(shí)如果運(yùn)行時(shí)庫不匹配也會(huì)出現(xiàn)各種意料之外的崩潰或者程序根本跑不起來等情況。
此時(shí)如果兩者作為對(duì)比就會(huì)很明顯看到多線程MT編譯出來的文件體積要比多線程MD編譯出來的大,因?yàn)镸T是把對(duì)應(yīng)的運(yùn)行時(shí)庫直接放到編譯出來的PE文件當(dāng)中,而MD卻是運(yùn)行的時(shí)候從第三方dll中獲取運(yùn)行時(shí)庫,自己本身卻不包含。同時(shí)另外的區(qū)別也很明顯,多線程MT編譯出來的文件運(yùn)行時(shí)不需要加載第三方dll所以運(yùn)行效率要比多線程MD稍微高一點(diǎn)點(diǎn),當(dāng)然作為用戶是完全感覺不到的。所以說如果打開一個(gè)程序目錄,發(fā)現(xiàn)里面有類似msvcrtXX.dll,那么這個(gè)程序幾乎可以肯定是用多線程MD方式編譯的。 以上區(qū)別一言以蔽之就是多線程MT加載的是靜態(tài)運(yùn)行時(shí)庫,屬于C語言版本;而多線程MD版本加載是動(dòng)態(tài)運(yùn)行時(shí)庫,屬于微軟版本。
|
|