多进程共享动态链接库的原理

时间:2022-02-13 06:06:40
  当多个进程共享dll时,其实内存中只保留一份dll代码,而每个进程调用dll的导出函数或类等等时是单独在进程的堆栈上分配空间的,也就是说每个调用dll的进程单独保留自己使用到的数据,各个进程互不影响。所谓的多进程共享其实就在内存中保留dll代码的空间内“做文章”,如多个进程共享一个dll时,使用LoadLibrary和GetProcAddress得到的地址是一样的,也说明内存中保留一份dll,每个进程共享dll     以下为详解(感觉不错转载的)   今天总结一下这个问题?为什么一个进程用完一个动态链接库以后另一个进程还可以继续使用呢?当时回答的很是笼统,只说对了答案的一半,现在就在这里好好总结一下吧!
前面我们已经说过进程间的通信有好几种方式,其实现在我们讲的这种动态链接库也是进程间的通信方式之一。
不管是windows还是Linux操作系统其实所有的操作系统的内涵知识都是一样的。
动态链接库是windows操作系统的基础,其中windows API基本上都是以动态链接库的形式来提供的,通常来说动态链接库是不能够直接运行,也不能直接接收消息的,他们是一些独立的文件(后缀名一般为.dll,当然还有其它的一些后缀名也是可以的),其中包含能被可执行程序或其它DLL调用来完成某项工作的函数,也就是说动态链接库也就是由一些函数组成而已。并且只有在其它模块调用动态链接库中的函数时,动态链接库才发挥作用,在实际的编程中,通常可以完成某种功能的函数放在一个动态链接库中,然后提供给其它函数调用。当这个访问了的动态链接库的进程被加载时,系统会为这个进程分配4GB的私有地址空间(如果是32位机的话),然后系统就会分析这个可执行模块,找到这个可执行模块中将所要调用的DLL,然后系统就负责搜索这些DLL找到这些DLL后便将这些DLL加载到内存中,并为他们分配虚拟内存空间,最后将DLL的页面映射到调用进程的地址空间汇总,DLL的虚拟内存有代码页和数据页,他们被分别映射到进程A的代码页面和数据页面,如果这时进程B也启动了,并且进程B也许要访问该DLL,这时,只需要将该DLL在虚拟内存中的代码页面和数据页面映射到第二个进程的地址空间即可。这也表明了在内存中,只需要存在一份DLL的代码和数据。

多个进程共享 DLL 的同一份代码,很明显这样做可以节省内存空间的。

但是在 Windows 下(Linux中也是一样的),由于系统会为每一个进程分配 4GB 的私有地址空间,

 DLL 中的代码和数据也只是映射到了这个私有地址空间中,所以这些应用程序之间还是不能够相互影响的,

也就是说多个应用程序虽然是可以共享同一个 DLL 中的相同的代码的,

但是 DLL 为每一个进程保存的数据都是不相同的,

并且每一个进程都为 DLL 使用的全部数据分配了自己的地址空间,

举个最简单的例子,我的 DLL 中有一个函数为 int   Add(int    num1 ,   int    num2)

这个函数的作用是实现 num1   num2 相加并返回相加后的结果。

然后我有一个 进程 A  使用了这个 DLL ,并且其调用了函数  Add(10, 20),

然后我还有一个 进程 B 其也使用了这个 DLL ,并且其调用了函数 Add(30, 40),

那么对于 进程 A 中的数据 10  20 其实是保存在 进程 A 的私有地址空间中的,

而对于 进程 B 中的数据 30  40 则是保存在 进程 B 的私有地址空间中的,

上面这个简单的例子表明如果单单用这种简单的使用动态链接库的方式是不能够实现进程之间的通信的。

如果想利用动态链接库来实现进程间的通信的话,那么有一种方案可以试一试,

即从系统为动态链接库分配的那一块内存(系统需要将动态链接库加载到内存中)下手,

由于在内存中,动态链接库其实只存在一份,

其被所有需要调用该动态链接库中的函数的模块或者简单说是可执行程序所共享,

既然是共享的话,如果我在系统给动态链接库分配的这块内存中保存数据,

那岂不是可以被所有访问该动态链接库的可执行程序所获取或者说设置。

这样的话,我就可以使用 进程 A 来设置好这个共享内存中的数据,

然后 进程 B 就可以读取这个共享内存中的数据了,这不是也可以实现进程间的通信嘛,

这样看来的话,其思路其实和使用剪贴板是一模一样的了。

也是采用一块两个进程共享的内存来作为存放数据的中介。