首先,我已经找到了可以回答我问题的a few个引用。虽然我打算尽快阅读它们(即下班后),但我仍然会问这里,以防答案是微不足道的,并且不需要太多的补充知识。
以下是这种情况:我正在编写一个共享库(让它称之为libA.so),它需要在同一个内部维护一个连贯的内部(如在.c文件中声明的静态变量)状态处理。
程序P将使用该库(即P用-lA
编译)。如果到目前为止我理解了所有内容,P的地址空间将如下所示:
______________
| Program P |
| < |
| variables, |
| functions |
| from P |
| > |
| |
| < |
| libA: |
| variables, |
| functions |
| loaded (ie |
| *copied*) |
| from shared |
| object |
| > |
| < |
| stuff from |
| other |
| libraries |
| > |
|______________|
现在P有时会调用dlopen("libQ.so", ...)
。 libQ.so也使用libA.so(即使用-lA
编译)。由于所有事情都发生在同一个过程中,因此无论调用是来自P还是Q,我都需要libA以某种方式保持相同的状态。
我不知道这将如何在内存中翻译。它看起来像这样:
______________
| Program P |
| < |
| P stuff |
| > |
| |
| < |
| libA stuff, |
| loaded by P |
| > | => A's code and variables are duplicated
| |
| < |
| libQ stuff |
| < |
| libA stuff,|
| loaded by Q|
| > |
| > |
|______________|
......还是喜欢这个?
______________
| Program P |
| < |
| P stuff |
| *libA |
| *libQ |
| > |
| |
| < |
| libA stuff, |
| loaded by P |
| > | => A's code is loaded once, Q holds some sort of pointer to it
| |
| < |
| libQ stuff |
| *libA |
| > |
|______________|
在第二种情况下,保持单个过程的一致状态是微不足道的;在第一种情况下,它需要更多的努力(例如一些共享内存段,使用进程id作为ftok()
的第二个参数)。
当然,由于我对链接和加载的工作方式知之甚少,因此上图可能完全错误。据我所知,共享库可能位于内存中的固定空间,每个进程都访问相同的数据和代码。行为还可能取决于A和/或P和/或Q的编译方式。这种行为可能与平台无关。
答案 0 :(得分:5)
共享库的代码段存在于单个实例每个系统的内存中。但是,它可以映射到不同进程的不同虚拟地址,因此不同的进程在不同的地址看到相同的功能(这就是为什么进入共享库的代码必须编译为PIC的原因)。
共享库的数据段在每个进程的一个副本中创建,并由库中指定的任何初始值初始化。
这意味着库的调用者不需要知道它是否被共享:一个进程中的所有调用者都看到函数的相同副本和库中定义的外部变量的相同副本。
不同的进程执行相同的代码,但拥有各自的数据副本,每个进程只有一个副本。