为什么应用程序这么大?
Why are applications so large?
我做了一个复杂的手部检测软件,它总共只有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演示场景制作,他们有相当多的技巧来减少二进制大小,充分利用二进制中的每一个字节。
- 为什么导入Mixed native/CLR lib.dll的本机C++应用程序没有在Mixed lib.dll中的外部变
- 如果整个应用程序是虚拟映射的,为什么 new 会进行系统调用?
- 为什么从文件获取图标时应用程序有时会崩溃?
- 为什么Qt Creator的应用程序输出不能从spdlog记录器打印
- 适用于 macOS 的 Xcode 应用程序。这就是我设置从USB麦克风输入获取音频的方式。一年前工作,现在没有了。为什么
- 当我按 ALT 时,WINAPI 应用程序关闭,为什么?
- 为什么我的 C# 应用程序无法加载我的 C++ dll?
- 为什么在Visual Studio中用c ++编写GUI应用程序的代码与控制台应用程序的代码不同?
- 为什么'system'不应该在 Windows 特定的应用程序中使用
- 为什么使用 nullPtr 调用函数不会使我的应用程序崩溃
- 为什么无法在 Cocoa 应用程序调用的 C++ func 中嵌入自定义 Python 模块
- 当我尝试将一个向量元素的值分配给另一个向量元素时,为什么我的应用程序会崩溃
- 为什么Linux报告了我的应用程序的内存使用情况
- 为什么我的 MPI 应用程序会触发断点?
- 为什么我的应用程序即使我的应用程序也关闭,即使我有cin.get();
- 在图形应用程序中,为什么着色器会在运行时加载到应用程序中
- 为什么我需要运行一个应用程序作为Papi库工作的根源
- Windows编程:为什么我们要将lParam转换为CREATESTRUCT来获取应用程序状态
- 当我释放由CFFI生成的DLL分配的char*时,为什么我的应用程序会崩溃
- 为什么我们需要使用android工具链(或NDK)来编译在android应用程序上下文中运行的c/c++代码