/MT、/MD編譯選項,以及可能引起在不同堆中申請、釋放內存的問題


一、MD(d)、MT(d)編譯選項的區別

1、編譯選項的位置

以VS2005為例,這樣子打開:

1)         打開項目的Property Pages對話框

2)         點擊左側C/C++節

3)         點擊Code Generation節

4)         右側第六行Runtime Library項目

2、各個設置選項代表的含義

編譯選項

包含

靜態鏈接的lib

說明

/MD

_MT、_DLL

MSVCRT.lib

多線程、Release、DLL版本的運行時庫

/MDd

_DEBUG、_MT、_DLL

MSVCRTD.lib

多線程、Debug、DLL版本的運行時庫

/MT

_MT

LIBCMT.lib

多線程、Release版本的運行時庫

/MTd

_DEBUG、_MT

LIBCMTD.lib

多線程、Debug版本的運行時庫

簡單的說:

(1)/MD,表示運行時庫由操作系統提供一個DLL,程序里不集成。

(2)/MT,表示運行時庫由程序集成。

二、/MD、/MT的選擇

      1、為什么選擇/MD,不選/MT?

         (1)程序就不需要靜態鏈接運行時庫,可以減小軟件的大小;

         (2)所有的模塊都采用/MD,使用的是同一個堆,不存在A堆申請,B堆釋放的問題;

   (3)用戶機器可能缺少我們編譯時使用的動態運行時庫。(補充:如果我們軟件有多個DLL,采用/MT體積增加太多,則可以考慮/MD + 自帶系統運行時庫)

      2、為什么選擇/MT,不選擇/MD?

         (1)有些系統可能沒有程序所需要版本的運行時庫,程序必須把運行時庫靜態鏈接上。

     (2)減少模塊對外界的依賴。

      3、多個模塊,必須選擇相同的運行時庫。

三、選擇/MT需要解決的堆空間釋放問題

         不同的模塊各自有一份C運行時庫代碼、或者根本沒有C運行時庫,導致了各個模塊會有各自的堆。如果在A堆中申請空間,到B堆中釋放就會有崩潰,在模塊A申請的空間,必須在模塊A中釋放。

         附錄的DLL以及DLLUser代碼,以STL的string為例,通過修改編譯選項驗證了這個問題。string在賦值的時候需要釋放掉原來的內存空間,然后再申請新的內存空間存儲新的內容,如果跨模塊了,釋放的時候就存在“A模塊申請B模塊釋放”的問題,導致程序崩潰。

   (跨模塊釋放內存導致崩潰的內容,在《windows核心編程》第五版Page511談DLL和進程的地址空間時有談到

四、選擇/MD需要注意多個模塊使用不同版本運行時庫的問題

  (2012-9-17補充)

  (2013.5.30補充)

     多個dll被一個exe LoadLibrary加載,如果這些dll使用的運行時庫是不同的,那么可能出現加載失敗,原因可能是舊版本的運行時庫已經在了,而某個dll它需要的是新版本的運行時庫,舊版本不符合要求。

     如果工程里所有的模塊都是自己寫的或者可以完全控制的,那么這個問題不難解決,只需要在工程設置里都設置/MD,然后在相同的環境下編譯一次就行。但是假如這個模塊是外界提供的呢?

     可能存在這種情況:A動態庫使用了B靜態庫,B靜態庫使用了C動態庫,B靜態庫是外界提供的,我們要使用它,但無法修改它,我們也無法接觸到C動態庫。如果C動態庫使用的運行時庫版本跟編譯A動態庫的本地使用的不一致,那么A動態庫里的嵌入信息就會記錄兩個不同版本的運行時庫,它被加載的時候,可能會選擇版本新的。假設A動態庫被一個exe LoadLibrary加載,而這個exe本身的運行時庫是舊的,這樣就會導致A動態庫加載失敗,即便把新的運行時庫拷貝到目錄下也不行,因為exe這個進程已經加載了那個舊的運行時庫。這時候必須使用manifest文件指定嵌入到A動態庫里的運行時庫為某個版本,忽略掉C動態庫使用的運行時庫版本。

     這個問題挺復雜的,我心思沒去驗證windows的PE文件加載會對運行時庫做什么樣的優先選擇、運行時庫在靜態庫里的記錄…。只要記住,給外界使用的組件版本盡量避免使用/MD(這樣會導致膨脹嗎?據說,安裝包可以做字節流式壓縮)。

  附上另一個問題:靜態庫的依賴關系:exe-->libA-->libB,現在不想讓exe接觸到libB,於是把libA的librarian選項-->General選項-->Link Library Dependencies設置為Yes,這樣即可,libA會包含libB,exe只需要接觸libA。另外需要特別注意,libA對libB的依賴只需要且只能在Solution的Project Dependencies里設置,如果在libA的代碼里寫了”#pragma comment(lib, "libB.lib")”,會導致exe在link libA的時候提示找不到libA。如果exe還出現link錯誤,那一定是VS抽筋了:)

五、參考資料

1、微軟關於MT、MD等的詳細介紹

http://msdn.microsoft.com/en-us/library/2kzt1wy3(v=VS.71).aspx

2、不要出現A模塊申請,B模塊釋放的情況

http://www.cnblogs.com/minggoddess/archive/2010/12/15/1907179.html

3、運行時庫有哪些版本

http://www.cppblog.com/MichaelLiu/articles/10607.html

4、CSDN上關於堆空間釋放的討論

http://topic.csdn.net/t/20010112/09/57983.html

http://topic.csdn.net/t/20031009/17/2338051.html

http://topic.csdn.net/u/20090502/00/bf1602e3-ddf5-49b0-af81-8a23383f9ddc.html

http://blog.csdn.net/blz_wowar/article/details/2176536

5、不同模塊不同的堆

http://www.cnblogs.com/WengYB/archive/2011/08/18/2144727.html

6、因為運行時庫版本問題導致加載失敗的分享

http://blog.csdn.net/dev_yarin/article/details/6768373

http://blog.163.com/henan_lujun/blog/static/19538333200611485511640/

7、《windows核心編程》

8、windows heap跟CRT heap

http://social.msdn.microsoft.com/Forums/vstudio/en-US/1e67edb1-9c2f-4f30-985a-7a0969366b1a/windows-heap-vs-crt-heap?forum=vcgeneral

http://msdn.microsoft.com/en-us/library/ms810466.aspx

附錄:

Demo代碼下載地址:http://files.cnblogs.com/cswuyg/Test_MD_and_MT.rar

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM