最近写的模块,在独立的应用程序中测试是没问题的,但把它装配成DLL后,再在另一个应用程序中调用时却出现了内存错误。程序的模块链接关系大概是这样的:

module就是我所写的模块,在这里被封装为DLL,因为要使用json相关的功能,该DLL链接了一个静态库 (jsoncpp.lib)。最后在应用程序中导入并使用module.dll,同时因为在应用程序中也需要用到json,所以应用程序也链接了jsoncpp.lib。

以下用一些伪代码来描述这些模块间的调用关系,以具现出这个错误。

jsoncpp.lib为c++提供了功能齐全的json操作,其核心的类是Json::Value。(阅读本篇文章你无需了解太多json)

module.dll中导出了一个接口:

//ModuleClass.h
#include "json/value.h"#if defined MODULE_EXPORTS
#define MODULE_EXPORTS __declspec(dllexport)
#else
#define MODULE_EXPORTS __declspec(dllimport)
#endifclass ModuleClass
{
public:MODULE_EXPORTS void AllocSomeMemory( Json::Value &root ){// 这将申请一些内存,因为会new出一个Json::Value,并append到root上root.append( "testString" );}
};
应用程序:

1 #include "json/value.h"
2 #include "ModuleClass.h"
3 int main()
4 {
5     Json::Value root;
6     ModuleClass::AllocSomeMemory( root );
7 }
在Debug模式下,当main函数执行完毕,对Json::Value root进行析构时,程序便出现了异常。分析下,很显然,调用ModuleClass::MallocMemoryHere时申请的内存,是在module.dll中申请的,而对这些内存的析构则是在应用程序(.exe)中进行的(析构root会同时析构append在root上的所有子Json::Value)。不过,这是异常的真正原因么?追踪到异常的出错点:dbgheap.c文件中那句ASSERT语句。
1 /*
2 * If this ASSERT fails, a bad pointer has been passed in. It may be
3 * totally bogus, or it may have been allocated from another heap.
4 * The pointer MUST come from the 'local' heap.
5 */
6 _ASSERTE(_CrtIsValidHeapPointer(pUserData));
注释中的最后一句话”The pointer MUST come from the ‘local’ heap“引起了我的警惕,难道对于内存的申请和释放不是在同一个heap上,除了‘local’ heap还有一个什么heap么。去MSDN上搜索了关于_CrtIsValidHeapPointer,似乎找到了答案,以下这段话是MSDN上对于_CrtIsValidHeapPointer的介绍:

The _CrtIsValidHeapPointer function is used to ensure that a specific memory address is within the local heap. The local heap refers to the heap created and managed by a particular instance of the C run-time library. If a dynamic-link library (DLL) contains a static link to the run-time library, it has its own instance of the run-time heap, and therefore its own heap, independent of the application’s local heap. When _DEBUG is not defined, calls to _CrtIsValidHeapPointer are removed during preprocessing.

注意字体加粗的部分,这不正应对我的情形么?!错误不在于DLL中申请的内存在EXE中释放,而在于如果这个DLL拥有一个静态链接,它就会拥有独立的运行时堆,独立于应用程序的堆。这样对于内存申请和释放并不是在同一个堆上进行的,当然出错了。解决:虽然MSDN上最后说,如果把项目改成release的,这个ASSERT就将避免,但这是放纵内存泄露,最好的解决办法是将静态链接也改成动态链接,这样就使得DLL能够和应用程序共享同一个堆,错误也得以避免。于是,我修改了jsoncpp的项目配置,生成jsoncpp的动态链接库,而不是使用静态库,重新导入到module.dll中,错误解决。

小心DLL链接静态库时的内存错误相关推荐

  1. 链接静态库时__imp_前缀错误

    visual studio 中链接静态库, 出现找不到 __imp_函数名 的错误, extern "C"也增加了 找到一段 Logically, the next questio ...

  2. 链接静态库的顺序问题

    在链接静态库时,如果多个静态库之间存在依赖关系,则有依赖关系的静态库之间存在顺序问题,这个在使用静态库时,需要注意,否则会报符号找不到问题,举例: libb.a依赖于是liba.a,而可执行文件tes ...

  3. 动态库、静态库编译测试:含静态库链接动态库、静态库,动态库链接静态库、动态库

    本文的目的是测试各种类型库的编译后的使用效果,包括库又链接其他库的编译方法,使用方法,依赖性等. 太长不看版:请跳至文章最后的总结对比表. 一.内容包含: ①静态库libbb.a依赖静态库libaa. ...

  4. 因链接静态库先后顺序不正确,引起符号定义找不到

    问题 项目中需要链接多个静态库,在编译的时候报错如下 sdi_io.cpp:(.text._ZN13sdi_H264EncIO7DataPopEPm+0x30):对'H264ENC_StatusGet ...

  5. [转]在Visual C++中以错误的顺序链接 CRT 库和 MFC 库时出现 LNK2005 错误

    症状 当 C 运行时 (CRT) 库和 Microsoft 基础类 (MFC) 库的链接顺序有误时,可能会出现以下 LNK2005 错误之一: nafxcwd.lib... 当 C 运行时 (CRT) ...

  6. [iOS] 引用外部静态库时,(类别)目录方法无法加载问题

    [iOS] 引用外部静态库时,目录方法无法加载问题 这个 bug 在 xcode 4.3 以下会出现,4.3 以后已经修正了. 解决方法为:找到 target 的图标,更改其 Other Linker ...

  7. linux下编译自己的静态库时依赖其他的动态库,使用时出现“undefined reference to”

    对于我这个刚入IT行业不就得新手来说,在linux下链接库的时候总是会遇到各种各样奇葩的问题,最多的就是"undefined reference to"和"cannot ...

  8. 链接静态库时报can not be used when making a PIE object; recompile with -fPIE

    链接了一个SDK的静态库,报了大量的错误都是 can not be used when making a PIE object; recompile with -fPIE 后在编译选项中加了-no-p ...

  9. 安装VC++2015运行库时出现0x80240037错误(JT预览报错)

    [JT预览报错]原因是缺少C++2015运行库. [安装VC++2015运行库时出现0x80240037错误]原因是windows7系统缺少Windows6.1-KB2999226-x64.msu补丁 ...

最新文章

  1. 实战:基于深度学习和几何的3D边界框估计
  2. 指针的运用与strcpy函数的优化
  3. 斐波那契数列与阶乘---递归实现
  4. java io 读取多个对象_Java IO系列(五):读写对象ObjectOutputStream和ObjectInputStream详解...
  5. php vue联动查询,使用vue.js实现联动效果的示例代码
  6. git提交代码到自己的分支,并合并到主分支的完整流程。
  7. 编译Mysql 5.5时报do_abi_check错误
  8. 【面向对象】可变对象和不可变对象
  9. 这42个Python小例子,太走心~
  10. Python+django网页设计入门(8):网站项目文件夹布局
  11. LeetCode刷题(28)
  12. linux测试dvi接口,TeX Live DVI字体数据解析整数溢出漏洞
  13. jQuery实现瀑布流
  14. mysql期末作业_MySql期中作业
  15. Java cipher加密与解密
  16. 【python】注意力机制代码
  17. MySQL 是如何归档数据的呢?
  18. 声纳--成像声呐目标检测与跟踪技术研究 ---15年,哈工程,博士毕业论文
  19. 最新PHP/SG11扩展解密视频教程分享
  20. 用事实说话,我是如何快速入门一个新领域的

热门文章

  1. python语言变量随时声明_2. Go语言五种变量创建的方法
  2. 【渝粤教育】国家开放大学2018年春季 0105-21T酒店营销实务 参考试题
  3. [渝粤教育] 西南科技大学 投资经济学 在线考试复习资料(2)
  4. java如何通过grpc连接etcd_grpc通过 etcd 实现服务发现与注册-源码分析
  5. linux 命令行 解密,解密Linux终端命令 学好Linux
  6. 杀java_java怎么杀掉java进程
  7. oracle java 并发_【转】JAVA并发教程(ORACLE官网资料)
  8. NOIP模拟测试49·50「养花·折射·画作·施工·蔬菜·联盟」
  9. 在idea下开发出现404错误
  10. 【BZOJ1814】Ural 1519 Formula 1 插头DP