代码之家  ›  专栏  ›  技术社区  ›  Emile Cormier

在现代Linux发行版中,共享库真正节省了多少磁盘空间?

  •  4
  • Emile Cormier  · 技术社区  · 15 年前

    在静态与共享库的争论中,我经常听说共享库消除了重复,减少了整体磁盘空间。但在现代Linux发行版中,共享库真正节省了多少磁盘空间?如果所有程序都是使用静态库编译的,那么还需要多少空间?有没有人为典型的桌面Linux发行版(如Ubuntu)计算过这些数字?有可用的统计数据吗?

    附录:

    所有的答案都很有信息性,很受欢迎,但它们似乎是在扼杀我的问题,而不是试图回答它。卡莱布走上了正确的道路,但他选择了计算内存空间而不是磁盘空间的数字(我的问题是磁盘空间)。

    因为程序只“支付”它们所使用的静态库的部分,所以几乎不可能定量地知道所有静态库与所有共享库之间的磁盘空间差异是什么。

    既然我意识到这几乎不可能回答,我想把我的问题搞砸。但我将把它留在这里,以保存有信息的答案。

    所以,别再唠叨我选择答案了,我会选择最受欢迎的答案(即使它回避了问题)。

    5 回复  |  直到 15 年前
        1
  •  8
  •   Ignacio Vazquez-Abrams    15 年前

    我不知道你在哪里听到的,但是当驱动器空间接近每千兆字节几美分时,减少的磁盘空间主要是一个误区。共享库的真正收益来自于这些库的安全性和错误修复更新;使用静态库的应用程序必须用新库单独重建,而使用共享库的所有应用程序都可以通过仅替换几个文件立即更新。

        2
  •  6
  •   Andrew McGregor    15 年前

    共享库不仅可以节省磁盘空间,还可以节省内存,这一点更为重要。预链接步骤在这里很重要…您不能在同一个库的两个实例之间共享内存页,除非它们加载在同一个地址,预链接允许这样做。

        3
  •  4
  •   camh    15 年前

    共享库不一定能节省磁盘空间或内存。

    当应用程序链接到静态库时,只有应用程序使用的库的那些部分将被拉入应用程序二进制文件中。库存档文件(.a)包含对象文件(.o),如果这些文件被很好地分解,应用程序将只通过链接它使用的对象文件来使用较少的内存。共享库将在磁盘和内存中包含整个库,不管部分库是否由应用程序使用。

    对于桌面和服务器系统来说,这不太可能导致总体上的胜利,但是如果您正在开发嵌入式应用程序,那么尝试静态链接所有应用程序,以查看这是否会给您带来总体上的节约。

        4
  •  2
  •   Kaleb Pederson    15 年前

    好吧,也许不是答案,但是我会考虑节省内存。节省将基于第一个应用程序之后加载库的次数,因此,让我们使用一个快速脚本来了解每个库在系统上的节省量:

    #!/bin/sh
    
    lastlib=""
    let -i cnt=1
    let -i size=0
    lsof | grep 'lib.*\.so$' | awk '{print $9}' | sort | while read lib ; do
        if [ "$lastlib" == "$lib" ] ; then
            let -i cnt="$cnt + 1"
        else
            let -i size="`ls -l $lib | awk '{print $5}'`"
            let -i savings="($cnt - 1) * $size"
            echo "$lastlib: $savings"
            let -i cnt=1
        fi
        lastlib="$lib"
    done
    

    这将为我们节省每个库的成本,例如:

    ...
    /usr/lib64/qt4/plugins/crypto/libqca-ossl.so: 0
    /usr/lib64/qt4/plugins/imageformats/libqgif.so: 540640
    /usr/lib64/qt4/plugins/imageformats/libqico.so: 791200
    ...
    

    那么,总储蓄:

    $ ./checker.sh | awk '{total = total + $2}END{print total}'
    263160760
    

    所以,粗略地说,在我的系统中,我节省了大约250兆的内存。你的里程数会有所不同。

        5
  •  2
  •   Emile Cormier    15 年前

    我能够在不做大量下流工作的情况下,找到一个部分定量的答案。以下是我的(发脑)方法:

    1)使用以下命令生成具有安装大小和依赖项列表的包列表:

    dpkg-query -Wf '${Package}\t${Installed-Size}\t${Depends}
    

    2)分析结果并为每个包构建统计图:

    struct PkgStats
    {
        PkgStats() : kbSize(0), dependantCount(0) {}
        int kbSize;
        int dependentCount;
    };
    
    typedef std::map<std::string, PkgStats> PkgMap;
    

    在哪里? dependentCount 是指 直接地 依靠那个包裹。

    结果

    以下是我的系统中依赖最多的前20个软件包列表:

    Package             Installed KB    # Deps  Dup'd MB
    libc6               10096           750     7385
    python              624             112     68
    libatk1.0-0         200             92      18
    perl                18852           48      865
    gconf2              248             34      8
    debconf             988             23      21
    libasound2          1428            19      25
    defoma              564             18      9
    libart-2.0-2        164             14      2
    libavahi-client3    160             14      2
    libbz2-1.0          128             12      1
    openoffice.org-core 124908          11      1220
    gcc-4.4-base        168             10      1
    libbonobo2-0        916             10      8
    cli-common          336             8       2
    coreutils           12928           8       88
    erlang-base         6708            8       46
    libbluetooth3       200             8       1
    dictionaries-common 1016            7       6
    

    在哪里? Dup'd MB 是如果没有共享将被复制的兆字节数( = installed_size * (dependants_count - 1) ,为了 dependants_count > 1 )

    看到libc6在上面并不奇怪。:)顺便说一句,我有一个典型的Ubuntu9.10设置,安装了一些与编程相关的软件包,以及一些地理信息系统工具。

    一些统计数据:

    请注意,上面完全忽略了间接依赖性(即,所有内容至少都应该间接依赖于libc6)。我真正应该做的是构建一个所有依赖关系的图表,并将其作为我的统计数据的基础。也许我会找个时间来写一篇详细而严谨的长篇博客文章。