加载共享库和RAM使用率


40

我想知道Linux管理共享库的方式。(实际上,我说的是Maemo Fremantle,这是2009年发行的基于Debian的发行版,运行于256MB RAM上)。

假设我们有两个链接到libQtCore.so.4并使用其符号(使用其类和函数)的可执行文件。为了简单起见,我们将它们称为ab。我们假设两个可执行文件都链接到相同的库。

首先我们启动a。必须加载该库。它是整体加载还是仅在所需部分加载到内存(因为我们不使用每个类,因此仅加载有关所用类的代码)?

然后我们启动b。我们假设它a仍在运行。b也链接到libQtCore.so.4并使用一些使用的类a,但也使用了一些未被使用的类a。库是否会被双重加载(分别用于a和分别加载b)?或者他们将使用RAM中已经存在的相同对象。如果不b使用任何新符号并且a已经在运行,则共享库使用的RAM是否会增加?(或者差异不大)

Answers:


53

注意:我将假设您的计算机具有内存映射单元(MMU)。有一个不需要MMU的Linux版本(µClinux),此答案不适用于该版本。

什么是MMU?它是硬件 -处理器和/或内存控制器的一部分。了解共享库链接并不需要您确切了解MMU的工作原理,只是MMU允许逻辑内存地址(程序使用的地址)和物理内存地址之间存在差异。内存地址(实际存在于内存总线上的地址)。内存分为几页,在Linux上通常为4K。对于4k页,逻辑地址0–4095是页0,逻辑地址4096–8191是页1,等等。MMU将那些地址映射到RAM的物理页,每个逻辑页通常可以映射到0或1个物理页。给定的物理页面可以对应于多个逻辑页面(这是共享内存的方式:多个逻辑页面对应于同一物理页面)。请注意,这适用于任何操作系统;这是对硬件的描述。

在进程切换时,内核会更改MMU页面映射,以便每个进程都有自己的空间。进程1000中的地址4096可以(通常是)与进程1001中的地址4096完全不同。

几乎每当您看到一个地址时,它就是一个逻辑地址。用户空间程序几乎不会处理物理地址。

现在,还有多种构建库的方法。假设某个程序调用foo()了库中的函数。CPU对符号或函数调用一无所知,它只知道如何跳转到逻辑地址并执行在其中找到的任何代码。它可以通过两种方法来执行此操作(当库访问其自己的全局数据时,类似的情况也适用):

  1. 它可以对一些逻辑地址进行硬编码以对其进行调用。这要求将库始终加载到完全相同的逻辑地址。如果两个库需要相同的地址,则动态链接将失败,并且您将无法启动该程序。库可能需要其他库,因此,这基本上要求系统上的每个库都具有唯一的逻辑地址。但是,如果可以的话,速度非常快。(这是a.out的工作方式,以及预链接的设置方式)。
  2. 它可以对伪造的逻辑地址进行硬编码,并告诉动态链接器在加载库时以正确的地址进行编辑。加载库时,这花费了相当多的时间,但是之后非常快。
  3. 它可能会增加一个间接层:使用CPU寄存器保存加载库的逻辑地址,然后访问所有内容作为该寄存器的偏移量。这会给每次访问带来性能成本。

几乎没有人使用#1,至少在通用系统上没有。在32位系统(没有足够的存储空间)上,保持唯一的逻辑地址列表是不可能的,而在64位系统上,这是管理上的噩梦。不过,预链接是在每个系统的基础上进行的。

使用#2还是#3取决于库是否使用GCC -fPIC(与位置无关的代码)选项构建。#2没有,#3是。通常,库是使用构建的-fPIC,因此会发生#3。

有关更多详细信息,请参见Ulrich Drepper的如何编写共享库(PDF)

因此,最后,您的问题可以得到回答:

  1. 如果该库是使用构建 -fPIC(几乎可以肯定应该如此),则每个加载该库的进程的绝大多数页面都是完全相同的。您的流程ab可能装载在不同的逻辑地址库中,但那些将指向同一个物理页:内存将被共享。此外,RAM中的数据与磁盘上的数据完全匹配,因此只有页面错误处理程序需要时才可以加载它。
  2. 如果构建的库没有 -fPIC,那么事实证明该库的大多数页面都需要链接编辑,并且将有所不同。因此,它们必须是单独的物理页面(因为它们包含不同的数据)。这意味着他们没有共享。这些页面与磁盘上的内容不匹配,因此如果加载了整个库,我不会感到惊讶。当然,随后可以将其换出到磁盘(在swapfile中)。

您可以使用该pmap工具或直接通过检查中的各种文件来进行检查/proc。例如,这是pmap -x两个不同的新生成的bcs 的(部分)输出。请注意,pmap显示的地址通常是逻辑地址:

pmap -x 14739
Address           Kbytes     RSS   Dirty Mode  Mapping
00007f81803ac000     244     176       0 r-x-- libreadline.so.6.2
00007f81803e9000    2048       0       0 ----- libreadline.so.6.2
00007f81805e9000       8       8       8 r---- libreadline.so.6.2
00007f81805eb000      24      24      24 rw--- libreadline.so.6.2


pmap -x 17739
Address           Kbytes     RSS   Dirty Mode  Mapping
00007f784dc77000     244     176       0 r-x-- libreadline.so.6.2
00007f784dcb4000    2048       0       0 ----- libreadline.so.6.2
00007f784deb4000       8       8       8 r---- libreadline.so.6.2
00007f784deb6000      24      24      24 rw--- libreadline.so.6.2

您可以看到该库分为多个部分加载,并分别pmap -x提供了每个部分的详细信息。您会注意到两个进程之间的逻辑地址是不同的。您可以合理地期望它们是相同的(因为运行相同的程序,并且计算机通常是可以预测的),但是有一种称为地址空间布局随机化的安全功能可以有意地将它们随机化。

从大小(千字节)和驻留大小(RSS)的差异中可以看出,整个库段尚未加载。最后,您可以看到对于较大的映射,dirty为0,这意味着它与磁盘上的内容完全对应。

您可以重新运行pmap -XX,它会显示-取决于您运行的内核版本,因为-XX输出随内核版本的不同而有所不同-第一个映射Shared_Clean的176与完全匹配RSSShared内存意味着物理页面在多个进程之间共享,并且由于它与RSS匹配,因此意味着内存中的所有库都是共享的(请参阅下面的另请参见以了解共享与私有的进一步说明):

pmap -XX 17739
         Address Perm   Offset Device   Inode  Size  Rss Pss Shared_Clean Shared_Dirty Private_Clean Private_Dirty Referenced Anonymous AnonHugePages Swap KernelPageSize MMUPageSize Locked                   VmFlagsMapping
    7f784dc77000 r-xp 00000000  fd:00 1837043   244  176  19          176            0             0             0        176         0             0    0              4           4      0       rd ex mr mw me sd  libreadline.so.6.2
    7f784dcb4000 ---p 0003d000  fd:00 1837043  2048    0   0            0            0             0             0          0         0             0    0              4           4      0             mr mw me sd  libreadline.so.6.2
    7f784deb4000 r--p 0003d000  fd:00 1837043     8    8   8            0            0             0             8          8         8             0    0              4           4      0       rd mr mw me ac sd  libreadline.so.6.2
    7f784deb6000 rw-p 0003f000  fd:00 1837043    24   24  24            0            0             0            24         24        24             0    0              4           4      0    rd wr mr mw me ac sd  libreadline.so.6.2


也可以看看


这意味着预链接不再有用了(并且-fPIC用法在一段时间前已完全改变)?
Hauke Laging

@crisron感谢您的更正。仅供参考,Markdown将为您计数-我重复的渲染输出1. 是正确的。另外,我对您所做的内容进行了一些更改-“开始地址”是技术术语,我很可能会在中间加上“逻辑”而引起混乱。我更改了它以消除行话。此外,页面与这些地址相同,根据AFAIK,这些地址不可能是不同的页面。我再次尝试,交换订单,希望情况会更清楚。
derobert

该死的,现在这就是答案!!!
埃文·卡罗尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.