我知道动态链接在磁盘上较小,但在运行时使用更多RAM。为什么会这样?
答案 0 :(得分:2)
答案是“这取决于你如何衡量它”,以及“它取决于你在哪个平台上运行”。
静态链接使用较少的运行时RAM,因为对于动态链接,需要将整个共享对象加载到内存中(我将在一秒钟内对此语句进行限定),而使用静态链接时,只加载实际需要的那些函数。
以上陈述并非100%准确。仅加载实际包含您使用的代码的共享对象页面。这仍然比静态链接效率低得多,静态链接将这些功能压缩在一起。
另一方面,动态链接使用更少的运行时RAM,因为所有使用相同共享对象的程序在代码的RAM副本中使用相同的内容(我将在一秒钟内对此语句进行限定)。
以上是关于Unix系统的真实陈述。在Windows上,它不是100%准确。在Windows上(至少在32位Intel上,我不确定其他平台),DLL不是使用位置无关代码编译的。因此,每个DLL都携带需要加载的(虚拟内存)加载地址。如果一个可执行文件链接两个重叠的DLL,则加载器将重定位其中一个DLL。这需要修补DLL的实际代码,这意味着此DLL现在携带特定于此程序使用它的代码,并且无法共享。然而,这种碰撞应该是罕见的,并且通常是可以避免的。
为了举例说明,静态链接glibc
可能会导致您在运行时消耗更多RAM,因为在您的程序启动之前,该库很可能已经加载到RAM中。静态链接一些独特的库只有你的程序使用才能节省运行时RAM。中间案件介于两者之间。
答案 1 :(得分:2)
调用相同dll / so文件的不同进程可以共享包含代码或文本页面的只读内存页面。
然而,在给定的peogram中加载的每个dll必须具有用于可写全局或静态数据的其自己的页面。这些页面可能是4/16 / 64k或更大,具体取决于操作系统。如果静态链接,静态数据可以在一个页面中共享。
答案 2 :(得分:1)
程序在Linux,Windows,MacOSX,Android等常用操作系统上运行时,processes运行时有一些virtual address space。这使用virtual memory(由驱动kernel的MMU实施)。
阅读像Operating Systems: Three Easy Pieces这样的好书以了解更多信息。
因此程序不直接使用 RAM。 RAM是由内核管理的资源。当RAM变得稀缺时,系统将进行实验thrashing。另请阅读page cache和memory overcommitment(我不喜欢的功能以及我经常禁用的功能)。
当几个进程使用同一个库时,使用共享库的好处是,它的code segment只出现一次(技术上是paged) RAM。
然而,dynamic linking的开销很小(即使在内存中),例如解决relocations。因此,如果仅由一个进程使用库,则可能会比静态链接消耗更多的RAM。在实践中,你不应该在大多数时间打扰,我建议系统地使用动态链接。
实际上,对于大型进程(例如浏览器),数据和堆消耗的RAM比代码要多得多。
在Linux上,Drepper的论文How To Write Shared Libraries详细解释了很多内容。
在Linux上,您可以使用proc(5)和pmap(1)来探索虚拟地址空间。例如,在终端中尝试cat /proc/$$/maps
和cat /proc/self/maps
以及pmap $$
。使用ldd(1)找出程序的动态库依赖关系,例如: ldd /bin/cat
。使用strace(1)查找流程使用的syscalls(2)。与虚拟地址空间相关的内容包括mmap(2)和munmap
,mprotect(2),mlock(2),旧sbrk(2) - 过时 - 和execve(2)。< / p>