对于两个进程A和B,两者都使用库libc.so,libc.so只加载到内存中一次。当A和B都在同一主机和相同的rootfs上运行时,这是正常情况。
说到容器,如果A和B在不同的容器中运行,A和B是否共享相同的内存区域?
例如
imageA
- libc.so
- programA
imageB
- libc.so
- programB
我们使用 chroot 在不同的rootfs中运行A和B.两个libc.so是一样的。将libc.so加载到内存中两次吗?
答案 0 :(得分:12)
实际上,流程A&使用共享库libc.so 的B可以共享相同的内存。有点不直观,这取决于您使用的docker存储驱动程序。如果您使用的存储驱动程序可以将共享库文件公开为源自同一设备/ inode,当它们位于同一个docker层时,则它们将共享相同的虚拟内存缓存页。使用aufs,overlay或overlay2存储驱动程序时,共享库将共享内存,但在使用任何其他存储驱动程序时,它们不会共享内存。
我不确定为什么在Docker文档中没有明确显示这个细节。或许它是,但我只是错过了它。如果您尝试运行密集容器,它似乎是一个关键的差异化因素。
答案 1 :(得分:1)
通过比较主机上两个不同容器中进程的物理地址(/ proc / pid / pagemap),可以确定不同容器中的.so是否共享相同的物理内存。
# ps -ef | grep java | grep -v grep | awk '{ print $2 }'
3906
4018
# sudo pmap -X 3906 | grep -e "Address" -e "libpthread"
Address Perm Offset Device Inode Size Rss Pss Referenced Anonymous LazyFree ShmemPmdMapped Shared_Hugetlb Private_Hugetlb Swap SwapPss Locked Mapping
7f97d9249000 r-xp 00000000 fd:00 135202206 104 104 52 104 0 0 0 0 0 0 0 0 libpthread-2.27.so
# sudo pmap -X 4018 | grep -e "Address" -e "libpthread"
Address Perm Offset Device Inode Size Rss Pss Referenced Anonymous LazyFree ShmemPmdMapped Shared_Hugetlb Private_Hugetlb Swap SwapPss Locked Mapping
7fce739e1000 r-xp 00000000 fd:00 135202206 104 104 52 104 0 0 0 0 0 0 0 0 libpthread-2.27.so
# virt_to_phys_user 3906 0x7f97d9249000
0x59940000
# virt_to_phys_user 4018 0x7fce739e1000
0x59940000
这里3906
和4018
是在两个不同容器中运行的Java应用程序的两个实例的主机上的进程ID。我使用了virt_to_phys_user,这是一个简单的“ c”程序,用于从该link给定pid和虚拟内存的情况下转储物理内存。请注意,以上两个过程的物理地址都相同。另外请注意,两个实例具有相同的inode
地址,Pss
表示这些页面正在共享。
但是,正如前面提到的那样,此行为取决于所使用的存储驱动程序。我看到这可以在Ubuntu 18.04上的docker-ce和RHEL8上的podman(分别为overlay2和overlay fs)上运行,但是在带有devicemapper的RHEL 7.5上不起作用。
答案 2 :(得分:-2)
他们不会共享相同的RAM区域;无论如何,这都是虚拟化(带容器)的目的 - 用于(内存)资源隔离等。有关更多信息,请查看内存cgroup。这里有很好的链接animation。