我不能 100% 确定这是 U&L 问题还是SO问题。总的来说,我将它发布在 U&L 上,因为它与操作系统相关。
背景
据我所知,Linux 将通过将共享库(.so 文件)映射为写时复制来加载共享库(.so 文件)。这样做的一个优点是,共享同一个大型库的多个进程都将共享相同的物理 RAM,用于该库的大部分内容。
Docker 不一定会发生这种情况,因为进程在基于“映像”的自己的“容器”中运行,并且每个映像都包含它自己的共享库副本。这是故意的。它允许程序附带它们自己的依赖项(库),这些依赖项可能与系统上已安装的库有很大不同。
因此,在 docker 主机上本地运行的程序不会与在 docker 容器中运行的程序共享相同的库内存,因为 docker 容器中的程序已映射到库的不同副本。
Docker 层解释
Docker 镜像是分层创建的。每一层都添加到较低的一层,有时会覆盖现有文件。并非每个文件都在每一层中更改。
Docker 允许您通过向旧图像添加新层来创建新图像。发生这种情况时,您最终会得到多个共享相同图层的图像。这些图像共享一些相同文件的相同副本。
Docker 将这些层分开保存,至少在运行时之前是这样。例如:从 Docker Hub 拉取图像,Docker 通过获取每个图像的组成层来获取图像。它只获取它还没有的层。
我不知道的
在创建或运行容器时,Docker 必须将这些层组装成一个单一的连贯文件系统。我不知道它是怎么做到的。它可能:
- 将文件复制到一个地方
- 在一处创建硬链接
- 使用覆盖文件系统
根据它的作用,源自同一层的文件可能是相同的副本,或者它们可能是文件系统上的完全相同的文件。
这最终会影响文件被多个进程映射到内存时发生的情况。
我真正想发现什么?
我想知道从两个不同的图像运行两个容器是否会为源自单个层的单个共享库共享相同的 RAM。
至少在某些配置中,是的,容器可以共享不同映像中同一层中的文件的内存映射。
这是一个实验来证明这一点。我正在使用两个不同的图像,一个基于另一个:
我启动了两个容器,仅使用入口点 shell:
让我们检查一下这两个 shell 使用的 C 库:
两个映射库具有相同的设备和 inode,因此它们是同一个文件,并且它们的映射将在可能的情况下共享。