优化 Linux 内存使用技巧
与大多数类 Unix 操作系统一样,决定 Linux 性能的最重要因素通常是可用的物理内存量。对于习惯于 MS-DOS 等其他系统的用户来说,这通常是困惑的根源。由于许多 Linux 用户预算紧张,简单地购买更多内存并不总是可行的。本文介绍了一些方法,可以更好地利用您已有的内存。
Linux 实现了按需分页的虚拟内存系统。进程拥有巨大的(4 千兆字节)虚拟内存空间。当引用虚拟内存时,相应的页面会在磁盘和物理内存之间传输。
当没有更多可用的物理内存页时,内核会将一些较旧的页面交换回磁盘。(如果它们是未更改的代码页,则只需丢弃;否则,它们将被写入交换区。)
磁盘驱动器是机械设备;磁盘的读写速度比访问物理内存慢几个数量级。如果所需的总内存页数大大超过可用的物理内存,内核将开始花费更多时间交换页面而不是执行代码。系统开始抖动,速度降至爬行。如果这种情况增加到交换设备被完全利用的程度,系统实际上可能会停顿。这绝对是我们想要避免的情况。
当额外的物理内存未被使用时,内核会尝试将其用作磁盘缓冲区缓存。磁盘缓冲区将最近访问的磁盘数据存储在内存中;如果再次需要相同的数据,可以从缓存中快速检索,从而提高性能。缓冲区会动态地增长和缩小以使用可用的内存,尽管内存的使用优先级高于分页。因此,您拥有的所有内存都得到了充分利用。
为了了解您的内存状况以及您所做的任何更改是否带来了改进,您需要某种测量内存使用情况的方法。我们有哪些可用的工具?
当系统首次启动时,ROM BIOS 通常会执行内存测试。如果您还不知道,可以使用它来识别系统中安装(和工作)了多少物理内存。在我的系统上,它看起来像这样
ROM BIOS (C) 1990 008192 KB OK WAIT......
下一个有用的信息在 Linux 启动过程中显示。应显示如下输出
Memory: 7100k/8192k available (464k kernel code, 384k reserved, 244k data) ... Adding Swap: 19464k swap-space
这显示了内核加载到内存后可用的 RAM 量(在本例中为原始 8192K 中的 7100K)。您还可以查看交换空间是否已正确启用。如果内核启动消息滚动太快而无法读取,在许多系统上,您可以使用“dmesg”命令在稍后时间调用它们。
一旦 Linux 运行, “free” 命令可用于显示可用的总内存(应与启动时显示的内存匹配),以及显示内存使用量和可用量的细分。(如果您没有 “free” 命令,可以使用 “cat /proc/meminfo”。)物理内存和交换空间都显示出来。这是我的系统上的典型输出
信息以千字节(1024 字节)显示。“总计”内存是加载内核后可用的内存量。任何用于进程或磁盘缓冲的内存都列为“已用”。当前未使用的内存列在“可用”列中。请注意,总内存等于“已用”和“可用”列的总和。
指示为“共享”的内存指示了多少内存是多个进程共有的。诸如 shell 之类的程序通常运行多个实例。可执行代码是只读的,可以由运行 shell 的所有进程共享。
“缓冲区”条目指示当前用于磁盘缓冲的内存量。
“free” 命令还非常清楚地显示了交换空间是否已启用以及正在进行的交换量。
为了更好地理解内核如何使用内存,观察系统使用时 “free” 命令的输出是有启发性的。我将展示一些从我自己的系统获取的示例;我建议您自己尝试类似的实验。
在启动时,当一个用户登录时,我的系统报告以下内容
total used free shared buffers Mem: 7096 2672 4424 1388 1136 Swap: 19464 0 19464
请注意,我们有相当多的可用内存 (4.4MB) 和相对较小的磁盘缓冲区 (1.1MB)。现在观察在运行从磁盘读取数据的命令后情况如何变化。(在这种情况下,我键入了 ls -lR /。)
total used free shared buffers Mem: 7096 5104 1992 1396 3460 Swap: 19464 0 19464
我们看到磁盘缓冲区增加了 2MB 以上。这相应地增加了 “已用” 内存,并减少了可用内存。接下来,我启动 X Window 系统并检查结果
total used free shared buffers Mem: 7096 7016 80 3112 3792 Swap: 19464 8 19456
这导致已用内存增加到 7MB,仅剩下 80K 可用内存。增加是为了支持运行的额外进程(X 服务器、窗口管理器、xterm 等...)。请注意,磁盘缓冲区没有缩小,因为仍然有可用内存。请记住:“可用”内存意味着正在浪费的内存。
现在我启动 GNU chess 程序,让它自己对弈。这启动了两个相当大的程序的实例
total used free shared buffers Mem: 7096 7016 80 1080 860 Swap: 19464 5028 14436
我们现在看到磁盘缓冲区已缩小到小于 1MB,并且我们正在使用 5MB 的交换空间来容纳大型进程。由于交换,系统速度变慢,并且可以听到沉重的磁盘驱动器活动。仍然有少量可用内存。(内核试图阻止用户进程占用所有可用内存;它为“root”用户保留了一些内存。)
下一步是退出 X Window 系统以及在其下运行的应用程序;这是结果。
total used free shared buffers Mem: 7096 2444 4652 412 1480 Swap: 19464 728 18736
我们现在有大量可用内存,交换使用几乎消失(一些空闲程序可能仍然被交换出去),并且磁盘缓冲区再次开始增长。
“top” 和 “ps” 命令对于显示内存使用情况如何动态变化以及单个进程如何使用内存也非常有用。对于前面描述的场景,我们可以从 “ps” 的输出中看到,两个 chess 进程中的每一个都占用了近 8MB 的虚拟内存,显然超过了物理内存可以容纳的量,导致系统抖动。
USER PID %CPU %MEM SIZE RSS TTY STAT START TIME COMMAND ... tranter 282 4.1 34.4 7859 2448 v01 D 14:08 0:11 gnuchessx 40 5 tranter 285 7.9 30.7 7859 2180 v01 D 14:09 0:21 gnuchessx 40 5 ...
用于获取系统状态信息的另一个工具内置于虚拟控制台驱动程序中。这取决于您的键盘映射,但美国键盘的默认设置是使用 Scroll-Lock 键。按 <Alt><Scroll Lock> 显示 CPU 寄存器的当前值。<Shift><Scroll Lock> 组合显示内存信息,类似于 “free” 命令,但更详细。最后,<Ctrl><Scroll Lock> 将提供有关单个进程的信息,很像 “ps” 命令。
如果您的系统速度缓慢或似乎已崩溃,这些键可能特别方便。请注意,如果您正在运行 syslog 守护程序,则此信息可能会记录到文件中,而不是显示在控制台上。例如,在我的 Slackware 系统上,它被记录到文件 /var/adm/syslog 中。
现在我们有了可以使用的测量工具,是时候尝试改善内存状况了。第一步是在 Linux 启动之前——您的 ROM BIOS 设置程序有一些选项可能会增加可用内存量。许多系统可以将 ROM 地址范围影射到 RAM 中,因为它比 ROM 更快。但是,与 MS-DOS 不同,Linux 不使用 ROM BIOS 例程,因此禁用此功能可以释放接近 200K 的内存(如果您仍然偶尔运行 MS-DOS,则可能不想这样做)。
顺便说一句,现在也是查看您的其他设置选项并进行一些实验的好时机。您可以通过启用缓存和设置 CPU 时钟速度的选项来提高 CPU 性能。衡量这一点的一种方法是使用 Linux 启动时显示的 BogoMIPs 评级作为 CPU 速度的指标(但这并不总是准确的,因为众所周知,BogoMIPs 是“虚假的”)。如果您从硬盘启动 Linux,您还可以通过在启动时禁用软盘驱动器寻道来加快重启时间。不要一次更改太多设置,否则您可能不知道哪些更改产生了积极影响。务必写下您的原始设置,以防您的系统进入无法启动的状态。
您是否仍在运行安装 Linux 时附带的默认内核?如果是这样,那就太可惜了!内核内存是特殊的——与进程使用的内存页不同,内核永远不会被交换出去。如果您可以减小内核的大小,则可以释放可用于执行用户程序的内存(更不用说减少内核编译时间和磁盘存储)。
这里的想法是重新编译内核,只使用您需要的选项和设备驱动程序。Linux 发行版附带的内核通常编译了所有可能的驱动程序和文件系统,以便任何系统都可以从中启动。如果您没有网卡、CD-ROM、SCSI 等,则可以通过从内核中删除它们来节省大量内存。此外,如果您从未自己重新编译过定制内核,您就不能真正认为自己是 Linux 黑客。
如果有些驱动程序您只是偶尔需要,请考虑构建多个内核,并设置 LILO 以允许您在启动时选择备用内核。如果您有数学协处理器,您也可以考虑取出 FPU 仿真例程。您还可以删除您不需要的任何 Linux 文件系统。
更高级的 Linux 黑客可能想看看“模块”工具,它允许加载设备驱动程序。使用此工具,您可以动态添加和删除驱动程序,而无需重新启动。此工具已提供给内核黑客一段时间,现在已成为标准内核的一部分。此工具对于很少使用的设备(例如仅偶尔用于备份目的的磁带驱动器)特别有用。
最后,请确保您正在运行最新的内核。较新的内核(在大多数情况下)除了更稳定之外,还在内存使用方面进行了改进。
如果您开发自己的应用程序,或者编译从 Internet 或公告板系统获得的代碼,那么使用正确的编译选项可以减少内存使用量。启用优化通常会生成更小、执行速度更快且需要更少内存的代码。一些优化,例如内联函数,可能会使代码更大。您还应检查您的可执行文件是否是动态链接的并剥离了调试信息。
哪些优化是最佳的取决于具体的应用程序,甚至取决于所用编译器的版本;您可能希望进行实验。
一旦 Linux 启动并运行您的新内核,就该看看内存都去哪儿了。甚至在您登录之前,有多少进程在运行?
Linux 系统的最低要求通常是
init(这会启动所有其他进程)
update(这会定期将磁盘缓冲区写入磁盘)
一个 getty(登录后会变成您的 shell)
运行 “top” 并查看您的系统上正在运行的内容。您需要多少个 getty 进程?您真的需要所有其他进程,例如 lpd、syslogk、syslogd、crond 和 selection 吗?在独立系统上,您不需要运行完整的网络软件。
如果您正在使用支持多个运行级别的 init 包,您可能需要考虑定义几个不同的运行级别。这样,例如,您可以在完全联网和独立运行之间切换您的系统,从而在您不需要它们时释放资源。
您还可以检查一些较大的可执行文件,看看它们是否是使用适当的编译器和链接器选项构建的。要识别最大的程序,请尝试使用如下命令
ls -s1 /bin /usr/bin /usr/bin/X11 | sort -n | tail
严格来说,这只会找到最大的文件,但文件大小通常是程序内存需求的一个很好的指示。
Linux 下最常见的 shell 是 GNU BASH。虽然功能非常强大,但它也相当大。您可以通过使用较小的 shell(例如 Korn shell(通常称为 ksh 或 pdksh))来节省内存。
emacs 编辑器也很大;您可以使用较小的编辑器,例如 vi、jove,甚至 ed 来代替。
如果您运行了前面描述的命令行,那么您最大的二进制文件之一可能是 X 服务器。X Window 系统占用大量内存资源。
要考虑的第一个问题是,您真的需要运行 X 吗?使用虚拟控制台和选择服务,您可以拥有多个窗口,支持使用鼠标剪切和粘贴文本。尤其是在执行大型编译(例如内核)时,您应该考虑完全不运行 X 的选项。
还有一个名为 “mgr” 的窗口系统,可以替代 X 使用,但需要的内存更少。
如果您决定使用 X,那么您可以获得一些标准工具的替代品,这些工具需要更少的资源。“Rxvt” 类似于 xterm,但需要的内存明显更少。窗口管理器 “fvwm” 也将比其他管理器使用更少的资源,而 “rclock” 是一个基于 X 的小型时钟程序。Robert Nation 编写的这三个工具可以使在以前不断交换的机器上运行 X 成为可能。
您在 X 桌面上运行多少个程序?运行 “top” 以查看 xclock、xeyes、xload 以及您认为需要的所有其他好东西占用了多少内存。
由 Craig I. Hagan 组装的 “Tiny X” 包包含 Korn shell、fvwm 窗口管理器、rxvt、rclock、X 服务器以及运行 X 所需的最少其他文件。该软件包足够小,可以放在一张 3.5 英寸软盘上。还包括一些关于在 X 下节省内存的有用注释。
使用此处描述的技术,您可以在只有 4 兆字节内存的机器上相当好地运行小型 X 应用程序。在具有更多内存的机器上,相同的方法将允许您运行更大的应用程序并释放内存以用于磁盘缓冲。
本文中提到的软件可在许多 Internet 存档站点上找到,包括 sunsite.unc.edu 和 tsx-11.mit.edu。我建议获取 Linux 软件地图的副本,以帮助跟踪您需要的软件。
如果您想了解更多关于 Linux 内核如何实现内存管理的信息,请查看 Michael K. Johnson 撰写的 “The Linux Kernel Hackers' Guide”,它是 Linux 文档项目的一部分。该文档的附录 A 包括一份涵盖一般操作系统概念的书籍的详尽书目。
“How to Maximize the Performance of X” 定期发布到 Usenet 新闻组 news.answers,其中包含更多关于在小型系统上提高 X 性能的想法。