每个进程都有一个默认堆,在进程初始化的时候会创建这个默认堆,可以通过GetProcessHeap()获取默认堆的句柄。使用CRT时,也会有一个CRT堆,VS项目属性 ~ C/C++ ~ 代码生成 ~ 运行库,如果选择多线程DLL,则CRT堆初始化在DLL中,如果选择多线程,则会在进入_tmain函数之前。

要在同一个DLL中对变量进行内存分配和释放的根本原因在于:每个DLL都要保存一份全局变量和静态变量的拷贝;CRT库中将堆的句柄保存为一个全局变量,而堆中内存的分配和释放都要使用这个句柄。如果可执行程序和DLL都使用动态链接的CRT库(/MD,/MDd),那么CRT库只初始化一次(在其DLL中),每次内存分配和释放也只在CRT的DLL库中进行,这样使用唯一一个堆的句柄,就不会导致错误。
如果有一个DLL(称为D1)使用静态链接的CRT库(/MT,/MTd),可执行程序也使用静态链接的,那么D1中有一个堆的句柄,可执行程序中也有一个堆的句柄,两者进行内存分配和释放时使用各自的堆的句柄。那么就必须保证使用D1分配的内存,必须由D1释放,否则就会出错。

问题重述

出现异常:Unhandled exception at 0x777F5624 (ntdll.dll) in xxx.exe: 0xC0000374: 堆已损坏
堆被破坏的问题通常是因为内存写越界造成的。因为你分配的两段内存可能恰好连续,前一段内存在写的时候越界,写到第二段的开头,将一些堆数据破坏了。因此报堆损坏的错。也可能是内存不足造成的。

最好不要跨模块new和delete,否则将会出现严重的错误(堆被破坏)。例如在DLL中使用new分配一块内存,之后在EXE中使用delete释放这块内存,有可能堆会被破坏,原因是,如果EXE和DLL都是用静态库的方式链接运行时库,此时EXE和DLL各自将有一个CRT堆,在一个堆上分配内存,之后在另一个堆上释放内存是肯定会发生错误的。如果EXE和DLL都是用动态库的方式链接运行时库,他们使用的是同一个CRT堆,则不会发错误。
一个模块一个堆,一个线程一个栈。dll里malloc的内存,在exe里free会出错。

问题解决

CRT(C运行时期库)不是使用进程缺省的堆来实现malloc(new中调用malloc)的,而是使用一个全局句柄 HANDLE _crtheap 来分配内存的。这个_crtheap是在XXXCRTStartUp(CRT提供的进口点函数)中创建的。 而在dll中的new使用dll中的_crtheap句柄分配堆,在exe中的delete使用exe中的_crtheap释放堆,当然失败!
修复方法:EXE和所有的DLL都必须动态链接/MD到同一份CRT。
1。在DLL中输出一个函数给EXE调用,专门用来释放由DLL分配的内存;
2。用 GlobalAlloc()代替new,用GlobalFree()代替delete;
3。使用单一的堆,分配内存使用 HeapAlloc(GetProcessHeap(),0,size),释放内存使用HeapFree(GetProcessHeap(),0,p);
4。把dll和exe的Settings的C/C++选项卡的Code   Generation的Use   Run-time   liberary改成Debug  Multithreaded   DLL,在Release版本中改成Multithreaded   DLL;这样使用一个CRT了——MSVCRT.DLL。
5.无论这些第三方库是静态库还是动态库,或者同时有静态库和动态库(可以同时使用),必须保证在生成这些库时,使用的C Runtime库是同一个版本(/MT, /MTd, /MD,或者/MDd)【如果是VC的话,在项目属性->配置属性->C/C++->Code Generate->Runtime Library中设置】。 否则,在编译可执行文件时,会出现重复定义的问题,这是因为C Runtime库的不同版本之间的冲突造成的。所以,如果你要提供一个第三方库给别人使用,最好提供使用了不同C Runtime库的多个版本(/MT,/MTd,/MD,或者/MDd),以供选择。

运行时库的选择

转自:转https://blog.csdn.net/maverick1990/article/details/46649493

运行时库 可以采用的方式有:多线程(/MT)、多线程调试(/MTd)、多线程DLL(/MD)、多线程调试DLL(/MDd)、单线程(/ML)、单线程调试(/MLd)。其中以小写“d”结尾的选项表示的DEBUG版本的,没有“d”的为RELEASE版本。大型项目中必须要求所有组件和第三方库的运行时库是统一的,否则将会出现LNK2005井喷。

Reusable Library Switch Library Macro(s) Defined
Single Threaded /ML LIBC (none)
Static MultiThread /MT LIBCMT _MT
Dynamic Link (DLL) /MD MSVCRT _MT and _DLL
Debug Single Threaded /MLd LIBCD _DEBUG
Debug Static MultiThread /MTd LIBCMTD _DEBUG and _MT
Debug Dynamic Link (DLL) /MDd MSVCRTD _DEBUG, _MT, and _DLL

单线程运行时库选项/ML和/MLd在VS2003以后就被废了。

/MT和/MTd表示采用多线程CRT库的静态lib版本。该选项会在编译时将运行时库以静态lib的形式完全嵌入。该选项生成的可执行文件运行时不需要运行时库dll的参加,会获得轻微的性能提升,但最终生成的二进制代码因链入庞大的运行时库实现而变得非常臃肿。当某项目以静态链接库的形式嵌入到多个项目,则可能造成运行时库的内存管理有多份,最终将导致致命的“Invalid Address specified to RtlValidateHeap”问题。另外托管C++和CLI中不再支持/MT和/MTd选项。

/MD和/MDd表示采用多线程CRT库的动态dll版本,会使应用程序使用运行时库特定版本的多线程DLL。链接时将按照传统VC链接dll的方式将运行时库MSVCRxx.DLL的导入库MSVCRT.lib链接,在运行时要求安装了相应版本的VC运行时库可再发行组件包(当然把这些运行时库dll放在应用程序目录下也是可以的)。 因/MD和/MDd方式不会将运行时库链接到可执行文件内部,可有效减少可执行文件尺寸。当多项目以MD方式运作时,其内部会采用同一个堆,内存管理将被简化,跨模块内存管理问题也能得到缓解。

结论:/MD和/MDd将是潮流所趋,/ML和/MLd方式请及时放弃,/MT和/MTd在非必要时最好也不要采用了。

选项 说明

/MD

使应用程序使用运行时库的多线程并特定于 DLL 的版本。定义 _MT 和 _DLL,并使编译器将库名

MSVCRT.lib 放入 .obj 文件中。

用此选项编译的应用程序静态链接到 MSVCRT.lib。该库提供允许链接器解析外部引用的代码层。实际工作

代码包含在 MSVCR80.DLL 中,该库必须在运行时对于与 MSVCRT.lib 链接的应用程序可用。

当在定义了 _STATIC_CPPLIB (/D_STATIC_CPPLIB) 的情况下使用/MD 时,它将导致应用程序与静态多

线程标准 C++ 库 (libcpmt.lib) 而非动态版本 (msvcprt.lib) 链接,同时仍通过 msvcrt.lib 动态链接

到主 CRT。

/MDd

定义 _DEBUG_MT 和 _DLL,并使应用程序使用运行时库的调试多线程并特定于 DLL 的版本。它还使编

译器将库名 MSVCRTD.lib 放入 .obj 文件中。

/MT

使应用程序使用运行时库的多线程静态版本。定义 _MT 并使编译器将库名 LIBCMT.lib 放入 .obj 文件中

,以便链接器使用 LIBCMT.lib 解析外部符号。

/MTd

定义 _DEBUG 和 _MT。此选项还使编译器将库名 LIBCMTD.lib 放入 .obj 文件中,以便链接器使用

LIBCMTD.lib 解析外部符号。

/LD

创建 DLL。

将 /DLL 选项传递到链接器。链接器查找 DllMain 函数,但并不需要该函数。如果没有编写 DllMain

函数,链接器将插入返回 TRUE 的DllMain 函数。

链接 DLL 启动代码。

如果命令行上未指定导出 (.exp) 文件,则创建导入库 (.lib);将导入库链接到调用您的 DLL 的应用程

序。

将 /Fe(命名 EXE 文件)解释为命名 DLL 而不是 .exe 文件;默认程序名成为basename.dll 而不是

basename.exe。

除非显式指定 /MD,否则将暗指 /MT

/LDd

创建调试 DLL。定义 _MT 和 _DEBUG

C++堆被破坏 运行时库相关推荐

  1. crt 运行时库dll跨模块传递crt对象,出现的崩溃问题

    参考链接: https://blog.csdn.net/weixin_30653097/article/details/96512399 (讲述了,运行时库在启动的时候在exe或dll入口点之前就使用 ...

  2. 如何在VS2005下生成动态运行时库

    如果我们的工程采用的是动态链接MFC库,那我们的程序如果拷贝到一个没有转VC的电脑中,我们的程序要想正确运行,除了拷贝程序外,还要将运行时库拷贝过去,下面记录下如何创建动态运行时库: file-> ...

  3. 什么是c/c++运行时库

    什么是c/c++运行时库 在各个版本的编译器中,我们可以通过配置选项来设置程序使用的C和C++运行时库的类型.如下图(其他版本编译器大同小异): MT选项:链接LIB版的C和C++运行库.在链接时就会 ...

  4. 近距离端详Android ART运行时库

    Table of Contents 在最新的Google I/O大会上,Google 发布了关于Android上最新的运行时库的情况.这就是Android RunTime (ART). ART 将会取 ...

  5. CRT(C Runtime Library)—— C/C++运行时库

    C runtime library(part of the C standard library) 任何一个 C 程序,它的背后都有一套庞大的代码来进行支撑,使得该程序得以运行在更高级别上,而不必担心 ...

  6. linux安装gcc运行时库,Linux安装gcc-6.1.0

    获取gcc源码包 # wget https://ftp.gnu.org/gnu/gcc/gcc-6.1.0/gcc-6.1.0.tar.bz2 # tar -jxvf gcc-6.1.0.tar.bz ...

  7. visual studio运行时库MT、MTd、MD、MDd 的区别

    msdn上面的解释: MT:mutithread,多线程库,编译器会从运行时库里面选择多线程静态连接库来解释程序中的代码,即连接LIBCMT.lib库 MTd:mutithread+debug,多线程 ...

  8. linux安装gcc运行时库,现在可以在CentOS 8系统下用命令安装GCC 8.3.1版本

    如果你需要在CentOS 8系统下安装GCC 8,则只需要运行相关的命令就可以了,现在安装的版本是GCC 8.3.1.如果你需要编译安装GCC源码包,则本文不适合你阅读,本文就介绍安装GCC最简单的方 ...

  9. c++ 判断电脑是否装有vc_redist.x86 运行时库

    Windows把卸载信息保存在注册表键HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows/CurrentVersion/Uninstall之下.我们可以枚举这个 ...

最新文章

  1. Pod在多可用区worker节点上的高可用部署
  2. 转行程序员深漂的这三年 #1
  3. 自考c语言程序阅读题,自考C语言程序设计模拟试题二答案.DOC
  4. python并行任务之生产消费模式
  5. 【跃迁之路】【737天】程序员高效学习方法论探索系列(实验阶段494-2019.2.27)...
  6. 算法点心----求出用1,2,5这三个数不同个数组合的和为100的组合个数。
  7. sans serif字体_30种免费的Sans Serif字体下载
  8. Echarts 柱状图使用
  9. C盘空间不足的处理方式
  10. 计算机无法安装新字体,在计算机上安装新字体
  11. 论文-《Conversational Recommender System》
  12. Java并发编程73道面试题及答案 —— 面试稳了 侵立删
  13. EXCEL表单元格内特定内容的提取
  14. PPPOE总结和配置
  15. Linux查看ice版本,转Linux下安装Ice过程
  16. Nodejs发送https Post请求时出现socket hang up错误的解决办法汇总
  17. SWT已经日薄西山(转载)
  18. 大学生电子设计大赛最全资料
  19. 转:伟大的进展,都源于承认无知,源于思想自由
  20. 英文连写字体怎么练_衡水体英文字体,你必须知道的技巧和注意事项!(建议收藏)...

热门文章

  1. kaggle-地震预测-LANL Earthquake Prediction
  2. 处理人际关系的技巧(转)
  3. 基于Java的开源论坛JForum的安装指南
  4. 使用RMAN传输数据_复制数据库
  5. 重庆市电信公司一百二十年简史
  6. 苹果2020年WWDC大会召开时间公布!这次5G技术会有怎样亮点?
  7. mysql子查询作为条件_sql - 使用子查询作为条件的MySQL DELETE FROM
  8. mysql时间条件查询
  9. 集成谷歌ADMob Request Error: No ad to show.
  10. 2023年海外营销趋势:这6点跨境卖家必须了解