为什么应用程序这么大?

Why are applications so large?

本文关键字:应用程序 为什么      更新时间:2023-10-16

我做了一个复杂的手部检测软件,它总共只有28KB左右的存储空间。我有大约600行代码,只有28KB。其他软件程序是如何做到这么大的(比如几gb)。我的意思是,我理解为什么游戏很大,但几天前我发现了一个简单的图片查看器,大约50MB。它是如何占据这么大的空间的?我说的是存储,而不是RAM

我主要想知道的是程序如何管理需要这么多的存储空间?

这取决于它们是用什么制作的,程序员的效率如何,可能最重要的是,资源。你的手部检测程序可能主要是算法,对吧?常见的软件可能包括诸如本地化(我知道notepad++的巨大尺寸主要归功于它的72种或更多语言和各种带有图像的帮助文件)以及图标,大图,启动屏幕,定制设计的表单……它们也可能是用。net或其他语言编写的,这是IL,包括版本检查代码和其他东西……这样的例子不胜枚举。

一些应用程序可能还包括他们使用的库打包在自己内部,以避免"丢失DLL"消息,或者他们可能包含静态库,也许他们打包字体或诸如此类的东西。

有很多不同的可能性

我有大约600行代码,只有28KB

600loc是一个微小的应用程序。复杂性是无关紧要的。此外,某些优化可以使代码"更大"但运行速度更快。最重要的是,一个可执行文件可能有许多直接编译到其中的资源,例如映像。一个小的,主要是算法的命令行实用程序并不是唯一的应用程序类型。

以我每天开发的应用程序为例。该项目有1,000,000多行代码,更不用说编译到其中的所有静态库代码。

您的应用程序人为地很小,因为您使用的是动态链接的库,并且严重依赖其他人提供的库来完成您的大部分处理。

让我们考虑我最喜欢的图像查看器,qiv:

$ ls -l /usr/bin/qiv
-rwxr-xr-x 1 root root 67048 2010-05-15 13:12 /usr/bin/qiv
$ size `which qiv`
   text    data     bss     dec     hex filename
  58586    4304    4968   67858   10912 /usr/bin/qiv

它相当小,但这是因为它协调了几十个动态库的操作:

$ ldd /usr/bin/qiv
    linux-vdso.so.1 =>  (0x00007fff2db9d000)
    libgdk-x11-2.0.so.0 => /usr/lib/libgdk-x11-2.0.so.0 (0x00007f7492ab3000)
    libgdk_pixbuf-2.0.so.0 => /usr/lib/libgdk_pixbuf-2.0.so.0 (0x00007f7492893000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f749260d000)
    libpangocairo-1.0.so.0 => /usr/lib/x86_64-linux-gnu/libpangocairo-1.0.so.0 (0x00007f7492400000)
    libpango-1.0.so.0 => /usr/lib/x86_64-linux-gnu/libpango-1.0.so.0 (0x00007f74921b6000)
    libcairo.so.2 => /usr/lib/libcairo.so.2 (0x00007f7491ef4000)
    libgio-2.0.so.0 => /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0 (0x00007f7491bc9000)
    libgobject-2.0.so.0 => /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0 (0x00007f7491978000)
    libgmodule-2.0.so.0 => /usr/lib/x86_64-linux-gnu/libgmodule-2.0.so.0 (0x00007f7491773000)
    libgthread-2.0.so.0 => /usr/lib/x86_64-linux-gnu/libgthread-2.0.so.0 (0x00007f749156e000)
    librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f7491366000)
    libglib-2.0.so.0 => /lib/x86_64-linux-gnu/libglib-2.0.so.0 (0x00007f7491076000)
    libImlib2.so.1 => /usr/lib/libImlib2.so.1 (0x00007f7490e0c000)
    libX11.so.6 => /usr/lib/x86_64-linux-gnu/libX11.so.6 (0x00007f7490ad2000)
    libXinerama.so.1 => /usr/lib/x86_64-linux-gnu/libXinerama.so.1 (0x00007f74908ce000)
    libmagic.so.1 => /usr/lib/libmagic.so.1 (0x00007f74906b1000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f7490493000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f74900fe000)
    libfontconfig.so.1 => /usr/lib/x86_64-linux-gnu/libfontconfig.so.1 (0x00007f748fec8000)
    libXext.so.6 => /usr/lib/x86_64-linux-gnu/libXext.so.6 (0x00007f748fcb6000)
    libXrender.so.1 => /usr/lib/x86_64-linux-gnu/libXrender.so.1 (0x00007f748faaa000)
    libXi.so.6 => /usr/lib/x86_64-linux-gnu/libXi.so.6 (0x00007f748f89a000)
    libXrandr.so.2 => /usr/lib/x86_64-linux-gnu/libXrandr.so.2 (0x00007f748f691000)
    libXcursor.so.1 => /usr/lib/x86_64-linux-gnu/libXcursor.so.1 (0x00007f748f486000)
    libXcomposite.so.1 => /usr/lib/x86_64-linux-gnu/libXcomposite.so.1 (0x00007f748f283000)
    libXdamage.so.1 => /usr/lib/x86_64-linux-gnu/libXdamage.so.1 (0x00007f748f080000)
    libXfixes.so.3 => /usr/lib/x86_64-linux-gnu/libXfixes.so.3 (0x00007f748ee79000)
    libpangoft2-1.0.so.0 => /usr/lib/x86_64-linux-gnu/libpangoft2-1.0.so.0 (0x00007f748ec4d000)
    libfreetype.so.6 => /usr/lib/x86_64-linux-gnu/libfreetype.so.6 (0x00007f748e9b3000)
    libpixman-1.so.0 => /usr/lib/libpixman-1.so.0 (0x00007f748e745000)
    libpng12.so.0 => /lib/x86_64-linux-gnu/libpng12.so.0 (0x00007f748e51d000)
    libxcb-shm.so.0 => /usr/lib/x86_64-linux-gnu/libxcb-shm.so.0 (0x00007f748e31a000)
    libxcb-render.so.0 => /usr/lib/x86_64-linux-gnu/libxcb-render.so.0 (0x00007f748e111000)
    libxcb.so.1 => /usr/lib/x86_64-linux-gnu/libxcb.so.1 (0x00007f748def5000)
    libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f748dcdc000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f748dad8000)
    libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007f748d89c000)
    libresolv.so.2 => /lib/x86_64-linux-gnu/libresolv.so.2 (0x00007f748d680000)
    libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f748d462000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f7492d8b000)
    libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007f748d237000)
    libXau.so.6 => /usr/lib/x86_64-linux-gnu/libXau.so.6 (0x00007f748d034000)
    libXdmcp.so.6 => /usr/lib/x86_64-linux-gnu/libXdmcp.so.6 (0x00007f748ce2d000)

如果我们看一下所有这些库的大小,我们看到实际上这个程序是巨大的,但是根据功能分成了几十个部分:

$ size -t `ldd /usr/bin/qiv | awk '/=> // {print $3;}'`
   text    data     bss     dec     hex filename
 710482   18672    1296  730450   b2552 /usr/lib/libgdk-x11-2.0.so.0
 122635    2448     384  125467   1ea1b /usr/lib/libgdk_pixbuf-2.0.so.0
 537611     804      72  538487   83777 /lib/x86_64-linux-gnu/libm.so.6
  44015    2056     176   46247    b4a7 /usr/lib/x86_64-linux-gnu/libpangocairo-1.0.so.0
 287233    8948     672  296853   48795 /usr/lib/x86_64-linux-gnu/libpango-1.0.so.0
 764734    8656   12552  785942   bfe16 /usr/lib/libcairo.so.2
1194267   19848    5936 1220051  129dd3 /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0
 316566    5184    3336  325086   4f5de /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
   8761     824     152    9737    2609 /usr/lib/x86_64-linux-gnu/libgmodule-2.0.so.0
  14097    1088      72   15257    3b99 /usr/lib/x86_64-linux-gnu/libgthread-2.0.so.0
  27388    1236    2536   31160    79b8 /lib/x86_64-linux-gnu/librt.so.1
 968533    3568    2280  974381   ede2d /lib/x86_64-linux-gnu/libglib-2.0.so.0
 344595    2340   83136  430071   68ff7 /usr/lib/libImlib2.so.1
1261924   17720    1864 1281508  138de4 /usr/lib/x86_64-linux-gnu/libX11.so.6
   5431     760      40    6231    1857 /usr/lib/x86_64-linux-gnu/libXinerama.so.1
 100837    2752    8776  112365   1b6ed /usr/lib/libmagic.so.1
  96934    1732   16776  115442   1c2f2 /lib/x86_64-linux-gnu/libpthread.so.0
1609087   18360   22104 1649551  192b8f /lib/x86_64-linux-gnu/libc.so.6
 210197    5624    1000  216821   34ef5 /usr/lib/x86_64-linux-gnu/libfontconfig.so.1
  67157    2512     648   70317   112ad /usr/lib/x86_64-linux-gnu/libXext.so.6
  36158    1088      56   37302    91b6 /usr/lib/x86_64-linux-gnu/libXrender.so.1
  59386     936     256   60578    eca2 /usr/lib/x86_64-linux-gnu/libXi.so.6
  29276     856      40   30172    75dc /usr/lib/x86_64-linux-gnu/libXrandr.so.2
  33972     968      40   34980    88a4 /usr/lib/x86_64-linux-gnu/libXcursor.so.1
   6615     624      40    7279    1c6f /usr/lib/x86_64-linux-gnu/libXcomposite.so.1
   5780     664      40    6484    1954 /usr/lib/x86_64-linux-gnu/libXdamage.so.1
  18261     728      40   19029    4a55 /usr/lib/x86_64-linux-gnu/libXfixes.so.3
 172803    3192     416  176411   2b11b /usr/lib/x86_64-linux-gnu/libpangoft2-1.0.so.0
 598232   20768      16  619016   97208 /usr/lib/x86_64-linux-gnu/libfreetype.so.6
 424774   17652     704  443130   6c2fa /usr/lib/libpixman-1.so.0
 153551    1852      16  155419   25f1b /lib/x86_64-linux-gnu/libpng12.so.0
   4552     936      16    5504    1580 /usr/lib/x86_64-linux-gnu/libxcb-shm.so.0
  26611    2544      16   29171    71f3 /usr/lib/x86_64-linux-gnu/libxcb-render.so.0
 106810    1208     176  108194   1a6a2 /usr/lib/x86_64-linux-gnu/libxcb.so.1
  90374    1320      16   91710   1663e /lib/x86_64-linux-gnu/libz.so.1
   7554     792     152    8498    2132 /lib/x86_64-linux-gnu/libdl.so.2
 237076    1032      24  238132   3a234 /lib/x86_64-linux-gnu/libpcre.so.3
  90932    3424   10328  104684   198ec /lib/x86_64-linux-gnu/libresolv.so.2
 111900    1564    4880  118344   1ce48 /lib/x86_64-linux-gnu/libselinux.so.1
 157434    8112      16  165562   286ba /lib/x86_64-linux-gnu/libexpat.so.1
   7153     712      32    7897    1ed9 /usr/lib/x86_64-linux-gnu/libXau.so.6
  16874     592      16   17482    444a /usr/lib/x86_64-linux-gnu/libXdmcp.so.6
11088562     196696  181144 11466402     aef6a2 (TOTALS)

那是 10兆字节的库。当然,并不是每个库都将被使用,但这是可执行文件中没有包含的10兆字节的代码。我猜想您的应用程序也是类似的——看看您的应用程序所需的库的大小,您可能也会更好地理解您所编写的代码的大小。

但是,当您看到巨大的可执行文件时,开发人员经常选择静态链接他们的库——这意味着它们是自包含的可执行文件,不依赖于系统提供任何特定的库。这将把所有库中使用的所有例程拖到主可执行文件中,这极大地"增长"了特定的可执行文件——在某种意义上,这是一个更好的指示大小的程序。

另一个促成因素是简单的膨胀——如果开发人员选择了错误的数据结构,它可能导致处理格式更改的代码过多,或者复杂的解析/格式化问题,或者在更具体的代码可以更小的情况下使用过于通用的代码。

要理解"代码膨胀"可能很难,但是一个好的第一个解释可能是Joel关于泄漏抽象的文章。但我们都能看到影响:我们的处理器比20年前快了几百倍,但许多"常规程序"比20年前大得多,以至于我们的应用程序运行速度大致相同。你见过Windows 3.1在"现代"系统上运行吗?它的速度快得令人印象深刻,但没有用户期望从图形化工作环境中获得的任何整洁的半透明效果。

静态链接会通过在最终二进制文件中直接包含库代码而导致代码膨胀。

您的应用程序大小约为28kB并不奇怪,这可能是因为您的构建环境将标准C/c++库链接到应用程序中。为了解决这个问题,你可以排除这些库与应用程序的链接,但你必须提供它们提供的最简单的功能。

查看4K演示场景制作,他们有相当多的技巧来减少二进制大小,充分利用二进制中的每一个字节。

相关文章: