1. 无论这些第三方库是静态库还是动态库,或者同时有静态库和动态库(可以同时使用),必须保证在生成这些库时,使用的C Runtime库是同一个版本(/MT, /MTd, /MD,或者/MDd)【如果是VC的话,在项目属性->配置属性->C/C++->Code Generate->Runtime Library中设置】。 否则,在编译可执行文件时,会出现重复定义的问题,这是因为C Runtime库的不同版本之间的冲突造成的。所以,如果你要提供一个第三方库给别人使用,最好提供使用了不同C Runtime库的多个版本(/MT, /MTd, /MD,或者/MDd),以供选择。我推荐使用/MD和/MDd,原因下面第4节中讲。
2. 一旦DLL的文件映像被映射到调用进程的地址空间中,DLL的函数就可以供进程中运行的所有线程使用。实际上,DLL几乎将失去它作为DLL的全部特征。 对于进程中的线程来说,DLL的代码和数据看上去就像恰巧是在进程的地址空间中的额外代码和数据一样。当一个线程调用DLL函数时,该DLL函数要查看线程的堆栈,以便检索它传递的参数,并将线程的堆栈用于它需要的任何局部变量。此外, DLL中函数的代码创建的任何对象均由调用线程所拥有,而DLL本身从来不拥有任何东西。 必须注意的是,单个地址空间是由一个可执行模块和若干个DLL模块组成的。这些模块中,有些可以链接到静态版本的C/C++运行期库,有些可以链接到一个DLL版本的C/C++运行期库,而有些模块(如果不是用C/C++编写 有一个很方便的方法可以解决这个问题。当一个模块提供一个用于分配内存块的函数时,该模块也必须提供释放内存的函数。让我们将上面的代码改写成下面的样子: 3. 问题: 答:因为malloc/free, new/delete 都是调用HeapAlloc/HeapFree 来实现来实现内存分配是释放的。查看Windows的API可以看到,这两个函数都需要一个Heap的HANDLE做为参数。CRT 库采用了全局变量来保存这个HANDLE。如果是静态链接, CRT库的代码会链接到各个dll中去,也包括这个全局变量。也就是说,每个静态链接的dll都有一个自己的全局堆句柄,他们自己都在这个句柄上使用内存。当一个dll释放另外一个dll分配的内存时由于使用的堆句柄不一致于是出错。当使用动态链接时,有于每个dll 都是去调用CRT库的dll函数来分配和释放内存的,使用的是同一个句柄,所以就没有这个问题。 答:不同进程之间对 dll 全局变量的访问操作系统可以区分的,平时大家共用一份,当某个进程改了某个全局变量时,操作系统会自动为这个进程生成一份这个变量的拷贝,(copy- on-write)让这个进程访问拷贝的内容而不会影响其它进程中这个变量的值,所以不需要手动做同步。
4. 总结 综上所述,要在同一个DLL中对变量进行内存分配和释放的根本原因在于:每个DLL都要保存一份全局变量和静态变量的拷贝;CRT库中将堆的句柄保存为一个全局变量,而堆中内存的分配和释放都要使用这个句柄。 如果可执行程序和DLL都使用动态链接的CRT库(/MD,/MDd),那么CRT库只初始化一次(在其DLL中),每次内存分配和释放也只在CRT的DLL库中进行,这样使用唯一一个堆的句柄,就不会导致错误。 如果有一个DLL(称为D1)使用静态链接的CRT库(/MT,/MTd),可执行程序也使用静态链接的,那么D1中有一个堆的句柄,可执行程序中也有一个堆的句柄,两者进行内存分配和释放时使用各自的堆的句柄。那么就必须保证使用D1分配的内存,必须由D1释放,否则就会出错。这也就是1中我推荐使用/MD的原因。
//////////////////////////////////////////////////////////////////////////////////////////////////// //文章被翻来覆去的。。。 //上面可能是原文,下面可能是转载人加上的,不过感谢他们的劳动成果, //拿下来慢慢看~ //////////////////////////////////////////////////////////////////////////////////////////////////// 1.因为 malloc/free, new/delete 都是调用 HeapAlloc/HeapFree 来实现来实现内存分配是释放的。查看 Windows 的 API 可以看到,这两个函数都需要一个 Heap 的 HANDLE 做为参数。CRT 库采用了全局变量来保存这个 HANDLE。如果是静态链接, CRT 库的代码会链接到各个 dll 中去,也包括这个全局变量。也就是说,每个静态链接的 dll 都有一个自己的全局堆句柄,他们自己都在这个句柄上使用内存。当一个 dll 释放另外一个 dll 分配的内存时由于使用的堆句柄不一致于是出错。当使用动态链接时,有于每个 dll 都是去调用 CRT 库的 dll 函数来分配和释放内存的,使用的是同一个句柄,所以就没有这个问题。 2. 不同进程之间对 dll 全局变量的访问操作系统可以区分的,平时大家共用一份,当某个进程改了某个全局变量时,操作系统会自动为这个进程生成一份这个变量的拷贝,(copy- on-write)让这个进程访问拷贝的内容而不会影响其它进程中这个变量的值,所以不需要手动做同步。
在网上找到一段文字,再结合adlay的解释基本上清楚了. |
|