我正在运行 apache2.4 Web 服务器,并注意到当我运行systemctl status apache2
或 时service apache2 status
,它显示正在使用 4.2GiB 的 RAM,这对于我拥有的 RAM 数量来说不是问题,但我很困惑,因为top
和htop
都显示只使用了 500MiB 的 RAM,更不用说systemctl
报告 apache2 单独使用了。为什么会这样,哪个是正确的?
操作系统信息(如果需要):
OS: Kali GNU/Linux Rolling x86_64
Kernel: 4.19.0-kali3-amd64
答案1
简而言之,systemctl
更全面地说明了进程使用的内存,并报告了整个服务的总内存使用情况,而 则更top
宽松地说明了单个进程使用的内存。对于像apache2
这样的运行多个进程的服务,systemctl
预计会比 显示的内存使用率高得多top
。
*nix 中的内存管理极其复杂,因为 RAM 是大多数操作的限制资源,因此需要投入大量工作才能最大限度地利用它。因此,存在不同类别的内存或内存使用情况。我本来想把它们全部列出来,但很快就变得有点疯狂了。
不过,我可以列出一些主要类别。最大的区别是 RAM 与磁盘。“内存”只是存储数据的地方。在负载较轻的系统中,程序所需的所有数据(包括程序代码本身)都在 RAM 中。随着更多程序需要访问更多数据,“内存”会扩展到包括存储在磁盘上的数据。在 RAM 和磁盘之间移动“内存”是高度优化的(并且很复杂),但由于内核可以做到这一点,因此它可以通过多种方式做到这一点。
以下是内存使用类别的简化、不完整的列表
- 我们所认为的内存使用情况是:存储在 RAM 中且在其他地方不存在的数据。
- 大部分内存使用情况:存储在 RAM 中供 CPU 使用的数据,但实际上只是存储在磁盘上的某些内容的副本,而磁盘才是数据应有的权威。例如,操作系统代码。
- 程序存储在 RAM 中但未使用的数据,因此内核将其暂时写入磁盘,以便为当前需要这些数据的人释放 RAM。这称为“交换”,因为内存在 RAM 和磁盘之间交换。
除了这些类别之外,我们还有:
- 共享内存,即多个进程同时使用的数据。如果您运行同一个程序的两个副本,则程序代码不需要复制,它可以存储在 RAM 中一次,然后两个进程就可以共享它。
- 保留内存。程序可以向内核请求一些内存来存储数据,但在程序真正开始使用之前,这些内存只是被保留,不会占用任何空间(内核内存管理数据结构之外的空间)。
- 虚拟内存。这实际上只是为程序分配内存地址,为很多事情提供了方便的抽象。它通常很大(我的笔记本电脑目前使用超过 5,000 GiB 的虚拟内存),其大小/使用情况无关紧要。
因此,当您问“这个程序使用了多少内存?”时,没有唯一的答案。对于这样一个模糊的问题,确实没有任何好的答案。(参见本文对于该问题的 6 种不同定义以及关于为什么它们难以回答的一些讨论。)因此,不同的程序会给你不同的答案,通常还附有标签。
类似这样的程序top
会尝试回答“如果我退出这个程序,会释放多少内存”这样的问题。Linuxtop
手册页提供了有关如何对内存进行分类以及显示内容的大量详细信息。
另一方面systemctl
试图解释所有的记忆服务
正在使用的内存和交换空间,以及某种程度上的共享和文件备份,以便能够自动限制资源使用量,甚至在程序使用过多内存时将其终止。它用于cgroups
对进程使用的内存进行更广泛的核算,这在 2.2 节“核算”中有详细描述本文。
因此,即使服务仅运行一个进程,由于systemctl
进程的总内存使用量包括它首先加载的任何共享页面(在任何其他进程之前)、它正在使用的任何交换、它正在使用的任何内存缓存(例如文件系统或网络缓冲区)以及可能的其他内容,因此它可以报告比更高的内存使用量top
。当服务运行多个进程时,显然您会期望内存使用量进一步上升。