cross-dll C++在不同模块内分配和释放内存问题

实际问题

在工作中,需要做一个网络通讯功能,领导要求封装为动态库;

动态库的简单工作流程和接口:

  • Init: 初始化
    • 读取对应文件中的网络配置参数;
  • Open: 打开
    • Open接口有个参数为回调函数,打开成功后网络库开始子线程工作,若接收到数据,调用回调函数,通知上层代码;
  • Read: 读取数据
    • 在工作线程接收到数据后,会将数据缓存起来,通知上层代码,此时上层代码可调用Read接口读取到缓存的数据;
  • Close: 关闭网络
    • 停止工作;

初版完成之后,Read接口类型为:

bool Read(char*& buffer, int& nBufferSize);

由于上层代码不能确认当前缓存中的数据大小,所以需要在接口Read内部进行内存分配,故传递指针的引用(char*&);

Read接口内会根据当前缓存中的数据大小为buffer分配内存,并将缓存数据拷贝到分配的内存中;

正常使用时,其他功能一切正常,但在释放Read接口中分配的内存时出现问题:

(为简化代码省略一些有效性判断)

{
   
	char* buffer = NULL;
	int nSize = 0;
	net.Read(buffer, nSize);
	
	//do something
	...
	
	delete[] buffer;
	buffer = NULL;
}

问题出现在上述第九行,在释放buffer时程序崩溃;

问题分析

经查阅资料,此问题为cross-dll问题,即:

一个模块分配的内存不应该由另一个模块释放,因为两个模块可能使用不同版本的C运行期库,甚至不使用C运行期库。

malloc/free(引用自:https://blog.youkuaiyun.com/wangqing_199054/article/details/19402767)
这两个函数是使用频率最高的两个函数,由于他们是标准C库中的一部分,所以具有极高的移植性。这里的"移植性"指的是使用他们的代码可以在不同的平台下编译通过,而不同的平台下的C Run-Time Library的具体实现是平台相关的,在Windows平台的C Run-Time Library中的malloc()和free()是通过调用Heap Memory API来实现的。值得注意的是C Run-Time Library拥有独立的Heap对象,我们知道,当一个应用程序初始化的时候,首先被初始化的是C Run-Time Library,然后才是应用程序的入口函数,而Heap对象就是在C Run-Time Library被初始化的时候被创建的。对于动态链接的C Run-Time Library,运行库只被初始化一次,而对于静态连接的运行库,每链接一次就初始化一次,所以对于每个静态链接的运行库都拥有彼此不同的Heap 对象。这样在某种情况下就会出问题,导致程序崩溃,例如一个应用程序调用了多个DLL,除了一个DLL外,其他的DLL,包括应用程序本身动态连接运行库,这样他们就使用同一个Heap对象。而有一个DLL使用静态连接的运行库,它就拥有一个和其他DLL不同的Heap 对象,当在其他DLL中分配的内存在这个DLL中释放时,问题就出现了。

也就是说,两个都使用动态运行期库的模块(exe或dll)之间不存在cross-dll问题,而使用静态运行期库的模块,与其它模块之间,即使也是使用静态运行期库的模块,总是存在cross-dll问题的。

解决方法

  1. 导出一个内存释放接口,专门用来在库中释放由Read接口中分配的内存
  2. 导出一个获取缓存大小的接口,在调用Read前先使用此接口,获取当前缓存的大小,并在库外分配好buffer的大小,Read接口内仅进行内存拷贝操作;
//释放内存接口
void 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值