Linux 如何在物理内存中避免共享库文本部分的多个副本?
当Linux加载共享库时,我的理解是,文本部分只加载一次到物理内存中,然后映射到引用它的不同进程的页表中 但是,在何处/谁确保/检查同一共享库文本节没有多次加载到物理内存中 加载程序或mmap()系统调用是否可以避免重复,或者是否有其他方法以及如何避免重复 编辑1: 我一定已经展示了到目前为止所做的工作(研究)。这是 试图跟踪一个简单的sleep命令Linux 如何在物理内存中避免共享库文本部分的多个副本?,linux,memory-management,process,shared-libraries,loader,Linux,Memory Management,Process,Shared Libraries,Loader,当Linux加载共享库时,我的理解是,文本部分只加载一次到物理内存中,然后映射到引用它的不同进程的页表中 但是,在何处/谁确保/检查同一共享库文本节没有多次加载到物理内存中 加载程序或mmap()系统调用是否可以避免重复,或者是否有其他方法以及如何避免重复 编辑1: 我一定已经展示了到目前为止所做的工作(研究)。这是 试图跟踪一个简单的sleep命令 $ strace sleep 100 & [1] 22824 $ execve("/bin/sleep", ["sleep", "100"
$ strace sleep 100 &
[1] 22824
$ execve("/bin/sleep", ["sleep", "100"], [/* 26 vars */]) = 0
brk(0) = 0x89bd000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=92360, ...}) = 0
mmap2(NULL, 92360, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7f56000
close(3) = 0
open("/lib/libc.so.6", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\0`G\0004\0\0\0"..., 512) = 512
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f55000
fstat64(3, {st_mode=S_IFREG|0755, st_size=1706232, ...}) = 0
mmap2(0x460000, 1426884, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x460000
mmap2(0x5b7000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x156) = 0x5b7000
mmap2(0x5ba000, 9668, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x5ba000
close(3) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f54000
...
munmap(0xb7f56000, 92360) = 0
...
然后检查该进程的/proc/pid/maps文件
$ cat /proc/22824/maps
00441000-0045c000 r-xp 00000000 fd:00 2622360 /lib/ld-2.5.so
...
00460000-005b7000 r-xp 00000000 fd:00 2622361 /lib/libc-2.5.so
...
00e3e000-00e3f000 r-xp 00e3e000 00:00 0 [vdso]
08048000-0807c000 r-xp 00000000 fd:00 5681559 /usr/bin/strace
...
在这里可以看到,libc.so.6中带有
PROT_READ | PROT_EXEC
的mmap2()的addr参数位于特定地址。这让我相信物理内存中的共享库映射是由loader管理的。共享库是由mmap()
syscall加载的,Linux内核是智能的。它有一个内部数据结构,将文件描述符(包含装载实例和inode编号)映射到其中的映射页面
动态链接器(其代码位于/lib/ld linux.so
或类似位置)仅使用此mmap()
调用映射库(然后重新定位它们的符号表),此页面级重复数据消除完全由内核完成
映射发生在
PROT_READ | PROT_EXEC | PROT_SHARED
标志上,您可以通过扫描任何工具(如strace/bin/echo
)轻松检查这些标志。Linux内核以及与此问题相关的所有相关系统都是开源的,可以查看源代码。@Someprogrammerdude这是真的,但是任何能够在内核中检查这一点的人,很久以前就学会了,尽管每个人都可能好奇,这是如何工作的。我一直在寻找文件描述符和inode编号的引用。感谢我的荣幸:-)如果一个答案解决了你的问题,你可以点击左边的管道图标来接受它。这是对回答者的奖励,同时也向未来的访问者表明,问题已经解决了。