关于DLL的内存管理
今天遇到了CrtIsValidHeapPointer的assert,研究一番,发现我的需求好像比较无解,请各位看官帮我缕一缕。
目前的情况是,我写了一个库,里面全部都是些公用的类,比如什么文件操作啊,内存管理啊,或者字符串之类,因为我都用单件把他们包成一个一个的类了,所以我就把他编译成静态库A.lib(如果是动态库就没问题,只是我懒得去写导出信息所以就将就静态库了)。
然后项目里有两个动态库工程,我们称之为B.dll C.dll,因为前面也说了嘛,很多公用的部分都是放在A.lib里的,所以B和C都依赖了A。
现在的情况是在B.dll里创造了一个A里面的classA对象,这个对象内部有一个new出来的堆空间,然后B把这个对象交给了C.dll,在C.dll运行时,调用了classA的某方法,方法里会删除内部的堆空间,造成了前文提到的assert。
原因现在明白了,我比较困惑的是解决方案:
1.是不是dll和lib混用都会导致类似的问题?
2.我目前的解决方案是,在lib里用GlobalAlloc和GlobalFree代替new和delete,这样做好吗?
3.比如我这种公用的库,最好是也编成DLL吗?然后把里面每个类都导出来?这样感觉好2啊。
还望指教。
[解决办法]
很明显这个属于跨模块内存管理的问题。你new的内存传递给你的dll,那么delete应该由你自己来完成而不是dll完成。
[解决办法]
如果 a 编译成静态库,有下面两种解决方法:
1.b.dll 和 c.dll 使用同一个款编译器编译(保证CRT库版本一致),编译选项都选择 /MD(/MDD),这样不需 要担心内存是谁释放的问题了,因为他们底层使用的是同一个Heap,可以随便使用!
2.不要在 b.dll 中分配内存,然后在 c.dll 中释放,因为他们底层使用的是不同的 Heap,可以在 b 中包装一下 a 提供的释放函数,再由c调用,这样 a 的分配和释放都是由 b.dll 控制的,在同一个堆内,就没事了!
如果 a 编译成动态库,那么
由于 a 内部得内存分配和释放都使用的是 a.dll 的堆,就不会堆不合法错误了。
[解决办法]
遵循一些原则:
1. 尽量避免是直接使用其他DLL里面的全局对象。 因为DLL释放的时候,在其中的全局对象也会被释放, 有可能引起访问违例
2. DLL中导出了分配资源的函数, 则同时要导出对应的释放函数,否则很容易写出在分配是用new,释放使用free的情况。
[解决办法]