一、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://msdn.microsoft.com/en-us/library/ms810466.aspx
附录:
Demo代码下载地址:http://files.cnblogs.com/cswuyg/Test_MD_and_MT.rar
/MT、/MD编译选项,以及可能引起在不同堆中申请、释放内存的问题的更多相关文章
-
MD(d)、MT(d)编译选项的区别
1.编译选项的位置 以VS2005为例,这样子打开: 1) 打开项目的Property Pages对话框 2) 点击左侧C/C++节 3) 点击Code ...
-
编程 MD(d)、MT(d)编译选项的区别
转:http://blog.csdn.net/nodeathphoenix/article/details/7550546 1.各个选项代表的含义 编译选项 包含 静态链接的lib 说明 /MD _M ...
-
/MT /MD /ML /MTd /MDd /MLd 的区别
Multithreaded Libraries Performance The single-threaded CRT is no longer ( in vs2005 ) available. Th ...
-
gcc -M -MM -MQ -MF -MT -MD
静态模式规则对一个较大工程的管理非常有用.它可以对整个工程的同一类文件的重建规则进行一次定义,而实现对整个工程中此类文件指定相同的重建规则.比如,可以用来描述整个工程中所有的.o 文件的依赖规则和编译 ...
-
-fomit-frame-pointer 编译选项在gcc 4.8.2版本中的汇编代码研究
#include void fun(void) { printf("fun"); } int main(int argc, char *argv[]){ fun(); return ...
-
VS2008 Debug与Release的本质区别(转)
如何设置:工具栏“生成”→“配置管理器”→“活动解决方案配置” 对于VS2008的初次使用者来说,常会遇到的编译问题时,Debug版本运行正常,但在Release版本则不稳定或无法运行.以下是对Deb ...
-
C/C++ Learning
目录 1. C/C++中的关键字2. C/C++中的标识符3. 编译选项MD(d).MT(d)编译选项的区别4. C++类模板.函数模板5. C++修饰符6. 调用约定7. 错误处理8. 环境表 9. ...
-
Debug与Release的区别
Debug版本包括调试信息,所以要比Release版本大很多(可能大数百K至数M).至于是否需要DLL支持,主要看你采用的编译选项.如果是基于ATL的,则Debug和Release版本对DLL的要求差 ...
-
[转]Debug 和 Release 编译方式的区别
本文主要包含如下内容: 1. Debug 和 Release 编译方式的本质区别 2. 哪些情况下 Release 版会出错 3. 怎样“调试” Release 版的程序 Debug 和 Releas ...
随机推荐
-
jboss入门学习1
环境准备 win8 jdk1.6 jboss4.0.5 oracle10g 修改jboss默认端口 server/default/conf/jboss-service.xml 1.WebService ...
-
Delphi对ini文件的操作
一.INI文件的结构:; 注释[小节名]关键字=值 INI文件允许有多个小节,每个小节又允许有多个关键字, “=”后面是该关键字的值. 值的类型有三种:字符串.整型数值和布尔值.其中字符串存贮在INI ...
-
bshare
function shareInit(){ $('.bshare').each(function(index, element) { var c1 = $('.p3-dialog').attr('ti ...
-
Openfire分析之三:ConnectionManager 连接管理(1)
Openfire是怎么实现连接请求的? XMPPServer.start()方法,完成Openfire的启动.但是,XMPPServer.start()方法中,并没有提及如何监听端口,那么Openfi ...
-
02_版本控制工具SVN
SubVersion: 安装:根据电脑版本选择安装64或32位的subversion,尽量不要选择中文或者有空格的目录安装 版本控制仓库: 创建命令:SVNadmin create 目录 启动SVN服 ...
-
java数组的声明、创建和遍历
一.数组的声明.创建 1.一维数组 先是声明 dataType[] arrayRefVar; // 首选的方法 数据类型[] 数组名; dataType arrayRefVar[]; // 效果相同, ...
-
Content-disposition中Attachment和inline的区别
1.Content-disposition中Attachment和inline的区别java web中下载文件时,我们一般设置Content-Disposition告诉浏览器下载文件的名称,是否在浏览 ...
-
搜索评价指标——NDCG
◆版权声明:本文出自胖喵~的博客,转载必须注明出处. 转载请注明出处:https://www.cnblogs.com/by-dream/p/9403984.html 概念 NDCG,Normali ...
-
[转贴]systemd 编写服务管理脚本
[转贴]sparkdev大神的博客, 关于 systemd的配置文件的 介绍, 自己之前二进制安装 k8s 时 超过一个 service文件 但是当时不明不白的. 现在再学习一下大神的文章 的确牛B ...
-
JavaScript基础-DAY1
JavaScript介绍 你不知道它是什么就学?这就是一个网页嵌入式脚本语言...仅此而已 JavaScript组成 一个完整的 JavaScript 实现是由以下 3 个不同部分组成的: 核心(EC ...