dll

来源:互联网 发布:淘宝大尺度买家秀店铺 编辑:程序博客网 时间:2024/05/03 00:11

ref:http://blog.csdn.net/immigrator/article/details/7560965

 

 

一、DLL被多个进程调用问题

Win32系统会确保内存中只有一个该DLL的拷贝,这是通过内存映射文件来实现的。不同的进程分别将这份DLL的代码段地址映射到自己的进程空间中,同时不同的进程在自己的进程空间分别有各自的一份该DLL的数据段拷贝。

这是因为,在Win32环境中,每个进程都有了它自己的地址空间,DLL函数中的代码所创建的任何对象(包括变量)都归调用它的进程所有。当进程在载入DLL时,操作系统自动把DLL内存地址映射到该进程的私有空间,也就是进程的虚拟地址空间,而且也复制该DLL的全局数据的一份拷贝到该进程空间。(在物理内存中,多进程载入DLL时,DLL的代码段实际上是只加载了一次,只是将物理地址映射到了各个调用它的进程的虚拟地址空间中,而全局数据会在每个进程都分别加载)。也就是说每个进程所拥有的相同的DLL的全局数据,它们的名称相同,但其值却并不一定是相同的,而且是互不干涉的。因此,如果不采取特别的措施,DLL中的数据段不能跨进程共享。如果将将数据段的属性修改为共享的,这样该数据将被映像到所有的使用到该DLL的进程,即多个进程将共享该数据段

二、既然代码段共享,如果进程A中修改DLL的代码内容,使用同一DLL的其它进程B是否受影响?

不会!

这就涉及到一个内存的COPY ON WRITE 机制问题。

一个dll,被很多进程调用,为什么代码段共享,数据段不共享?就是因为 进程A调用这个dll,运行过程中,dll的数据段肯定会改变,那数据段就会被COPY一份,原来的依然存在不受影响。

当进程B调用这个dll,仍然用的是最开始的数据段,它往里写时再COPY一份到自己的进程空间,这就保证了两个进程A和B互不影响。

而由于代码段一般是不会被更改的,所以才提到代码段共享这个概念。但如果用hook等技术,把代码改了,代码同样会被COPY一份之后再改,所以不会影响其它的进程,只会影响你改的进程。于是可以解释下面某位同学所做的实验了:

 

在这里我做了一个试验,编写一个DLL和一个加载DLL并调用DLL中一个函数的程序,分别用二个OD加载这二个可执行程序调用DLL中的函数,为了说明加载的这个DLL分别位于不同的进程,没有任何的共享关系,我把二个进程同时一步一步调试,都执行到加载完DLL后,DLL的加载地址是一样的都0X10000000,接着我在第一个进程中转到DLL加载的地方,把MZ头用00填充,再一下F9,结果程序显示找不到调用的函数,接着再转到第二个进程,也转到0X10000000去看一下,这里没有被改动的迹象。F9一下,可以执行成功。说明加载的DLL虽然都在0X10000000,但是它们位于不同的进程,是不会相互干扰的


概括来说,Copy-On-Write机制,无论是代码段还是数据区,在一般情况下,如果没有被修改,都会被映射到相同的内存上,因此当加载同一个dll的时候,内存中只有一份dll。如果有内容被修改后,会构造副本,重新映射

 

三、DLL中在堆上分配的空间,能否在主程序中直接释放?

通常不行,谁负责分配,谁就必须负责释放
 原因之一就是因为DLL的调用是有被计数的,为了防止还有调用程序正在引用DLL,你不应该在程序中释放内存. 比如有一部分共享内存的数据,在进程A中释放了,进程B任然在使用,肯定会出问题。所以让DLL自己来释放,自己来管理。

原因之二就是因为   malloc/free,   new/delete   都是调用   HeapAlloc/HeapFree   来实现来实现内存分配是释放的。查看Windows的 API可以看到,这两个函数都需要一个Heap的HANDLE做为参数。CRT库采用了全局变量来保存这个HANDLE。如果是静态链接,CRT库的代码会链接到各个dll中去,也包括这个全局变量。也就是说,每个静态链接的   dll或EXE   都有一个自己的全局堆句柄,他们都在自己的这个句柄上使用内存。当在一个 dll或EXE中释放另外一个dll分配的内存时,由于使用的堆句柄不一致于是出错。当使用动态链接时,由于每个dll都是去调用CRT库的dll函数来分配和释放内存的,使用的是同一个句柄,所以就没有这个问题。

四、DLL加载的顺序

一个进程开始运行时,先会检查自己的导入表,看一下依赖的DLL有哪些,发现有依赖的DLL,那么就检查内存中是否有这个DLL了。如果没有,DLL首先被调入Win32系统的全局堆栈,然后映射到调用这个DLL的进程的地址空间。如果存在了,直接映射该DLL的代码段地址。因此不管该进程有多少一个实例,这个过程都是要做的。然后涉及到DLL的初始化问题,参考http://www.cppblog.com/AutomateProgram/archive/2010/03/15/109718.html,写的很好。

原创粉丝点击