dlopen 是否创建多个库实例?

Does dlopen create multiple library instances?

在网上搜索后似乎找不到答案。

当我第一次使用 dlopen 时,它似乎比之后的任何时候都花费更长的时间,包括如果我 运行 它来自一个程序的多个实例。

dlopen 是否将 so 加载到内存中一次并让 OS 保存它,以便任何后续调用甚至来自程序的另一个实例都指向内存中的同一位置?

所以基本上一个程序的 3 个实例 运行 是指同一个 .so 的 3 个实例被加载到内存中,还是内存中只有一个实例?

谢谢

Does dlopen load up the so into memory once and have the OS save it so that any following calls even from another instance of the program point to the same spot in memory?

从单个进程中多次调用 dlopen 保证不会多次加载库。来自 man page:

   If the same shared object is loaded again with dlopen(), the same
   object handle is returned.  The dynamic linker maintains reference
   counts for object handles, so a dynamically loaded shared object is
   not deallocated until dlclose() has been called on it as many times
   as dlopen() has succeeded on it.

当第一次调用 dlopen 时,库会 mmap 进入调用进程。通常至少有两个单独的 mmap 调用:.text.rodata 部分(通常驻留在单个 RO 段中)被映射为只读,.data.bss 个部分被映射为读写。

来自另一个进程的后续 dlopen 执行相同的 mmap。然而,OS 不必从磁盘加载任何只读数据——它只是增加已为第一个 dlopen 调用加载的页面的引用计数。那就是分享在"shared library".

So basically does 3 instances of a program running a library mean 3 instances of the same .so are loaded into memory, or is there only one instance in memory?

取决于你所说的"instance"。

每个进程都有自己的一组(动态分配的)运行时加载器结构来描述这个库,每组都包含一个 "instance" 的共享库(可以在不同进程的不同地址加载) ).每个进程还将有自己的可写数据实例(使用写时复制语义)。但是只读映射都将占用相同的物理内存(尽管它们可以出现在每个进程中的不同地址)。