“缓存”内存实际上是免费的吗?

Rol*_*uhs 11 linux memory cache meminfo

运行时cat /proc/meminfo,您会在顶部获得这 3 个值:

MemTotal:        6291456 kB
MemFree:         4038976 kB
Cached:          1477948 kB
Run Code Online (Sandbox Code Playgroud)

据我所知,“Cached”值是 Linux 系统制作的磁盘缓存,如果任何应用程序需要更多 RAM,它将立即释放,因此 Linux 永远不会耗尽内存,直到 MemFree 和 Cached 都为零。

不幸的是,/proc/meminfo 没有报告“MemAvailable”,可能是因为它在虚拟服务器中运行。(内核版本为 4.4)

因此,出于所有实际目的,可用于应用程序的 RAM 是 MemFree + Cached。

这种观点正确吗?

sou*_*edi 11

在许多实际案例中,这种观点可能非常具有误导性。

内核现在在MemAvailable现场提供可用内存的估计。该值与MemFree + Cached.

/proc/meminfo:提供估计的可用内存[内核更改说明,2014]

许多负载平衡和工作负载放置程序检查 /proc/meminfo 来估计有多少可用内存。他们通常通过将“免费”和“缓存”相加来做到这一点,十年前这很好,但今天几乎肯定是错误的。

这是错误的,因为 Cached 包括不可作为页缓存释放的内存,例如共享内存段、tmpfs 和 ramfs,并且它不包括可回收的板坯内存,这些内存可以在大多数空闲系统上占用大部分系统内存很多文件。

目前,可以从 MemFree、Active(file)、Inactive(file) 和 SReclaimable 以及来自 /过程/区域信息。然而,这在未来可能会改变,并且用户空间真的不应该被期望知道内核内部来估计可用内存量。在 /proc/meminfo 中提供这样的估计更方便。如果将来情况发生变化,我们只需在一个地方进行更改。
...

Documentation/filesystems/proc.txt:
...
MemAvailable: 估计有多少内存可用于启动新应用程序,无需交换。根据 MemFree、SReclaimable、文件 LRU 列表的大小以及每个区域的低水印计算。该估计考虑到系统需要一些页面缓存才能正常运行,并且由于项目正在使用,并非所有可回收的平板都是可回收的。这些因素的影响因系统而异。

1. MemAvailable 详细信息

正如上面所说,tmpfs 和其他Shmem内存不能被释放,只能移动到交换。 由于包含此可交换内存,因此Cachedin/proc/meminfo可能会非常具有误导性Shmem。如果 tmpfs 中有太多文件,它可能会占用大量内存:-)。 Shmem还可以包括一些图形内存分配,这可能非常大。

MemAvailable故意不包括可交换内存。交换太多会导致长时间的延迟。您甚至可能选择在没有交换空间的情况下运行,或者只允许相对有限的空间。

我不得不仔细检查是如何MemAvailable工作的。乍一看,代码似乎没有提到这个区别。

/*
 * Not all the page cache can be freed, otherwise the system will
 * start swapping. Assume at least half of the page cache, or the
 * low watermark worth of cache, needs to stay.
 */
pagecache = pages[LRU_ACTIVE_FILE] + pages[LRU_INACTIVE_FILE];
pagecache -= min(pagecache / 2, wmark_low);
available += pagecache;
Run Code Online (Sandbox Code Playgroud)

但是,我发现它正确地将其Shmem视为“已用”内存。我在 tmpfs 中创建了几个 1GB 的文件。每增加1GBShmem减少MemAvailable1GB。所以“文件 LRU 列表”的大小不包括共享内存或任何其他可交换内存。(我注意到在计算“脏限制”的代码中也使用这些相同的页数)。

MemAvailable计算还假设您希望保留至少足够的文件缓存以等于内核的“低水位线”。或当前缓存的一半 - 以较小者为准。(它也对可回收板做出相同的假设)。内核的“低水位线”可以调整,但通常是系统 RAM 的 2% 左右。所以如果你只想粗略估计,你可以忽略这部分:-)。

当您运行firefox大约 100MB 映射到页面缓存中的程序代码时,您通常希望在 RAM 中保留 100MB :-)。否则,充其量您将遭受延迟,最坏的情况是系统将花费所有时间在不同的应用程序之间颠簸。所以MemAvailable是允许的RAM为这个很小的比例。它可能不够,或者可能过于慷慨。“这些因素的影响因系统而异”。

对于许多 PC 工作负载,“大量文件”这一点可能无关紧要。即便如此,我的笔记本电脑上目前有 500MB 的可回收平板内存(8GB 的​​ RAM)。这是由于ext4_inode_cache(超过 30 万个对象)。发生这种情况是因为我最近不得不扫描整个文件系统,以查找正在使用我的磁盘空间的内容:-)。我使用了命令df -x / | sort -n,但例如 Gnome 磁盘使用分析器会做同样的事情。

2. [编辑] 控制组中的记忆

所谓的“Linux容器”是从建立起来namespacescgroups并根据口味不同的其他功能:-)。它们可能提供足够令人信服的环境来运行几乎像完整的 Linux 系统一样的东西。托管服务可以像这样构建容器并将它们作为“虚拟服务器”出售:-)。

托管服务器还可以使用主流 Linux 中没有的功能构建“虚拟服务器”。 OpenVZ容器比主线 cgroup 早两年,并且可能使用“beancounters”来限制内存。因此,如果您只阅读文档或询问有关主线 Linux 内核的问题,您将无法确切了解这些内存限制是如何工作的。 cat /proc/user_beancounters显示当前使用情况和限制。 vzubc以更友好的格式呈现它。在上beancounters主要页面的文档的行名。

控制组包括对其中的进程设置内存限制的能力。如果您在这样的 cgroup 中运行您的应用程序,那么并非所有系统内存都可供应用程序使用:-)。那么,在这种情况下我们如何查看可用内存呢?

此接口在许多方面有所不同,具体取决于您使用的是cgroup-v1还是cgroup-v2

我的笔记本电脑安装使用 cgroup-v1。我可以跑cat /sys/fs/cgroup/memory/memory.stat。该文件显示了各种字段,包括total_rsstotal_cachetotal_shmem。shmem,包括 tmpfs,计入内存限制。我想您可以将其total_rss视为MemFree. 还有文件memory.kmem.usage_in_bytes,代表内核内存,包括slab。(我假设memory.kmem.还包括memory.kmem.tcp.和任何未来的扩展,尽管这没有明确记录)。没有单独的计数器来查看可回收的平板内存。为cgroup中-V1文件称击中内存限制并不会触发任何平板的内存回收。(该文档还有一个免责声明,称它“已过时”,您应该检查当前的源代码)。

cgroup-v2 是不同的。我认为根(顶级)cgroup 不支持内存记帐。cgroup-v2 仍然有一个memory.stat文件。所有字段对子 cgroup 求和,因此您无需查找total_...字段。有一个file字段,这意味着同样的事情cache做了。令人讨厌的是,我没有看到像rssinside这样的整体领域memory.stat;我想您必须将各个字段相加。可回收和不可回收的平板内存有单独的统计信息;我认为 v2 cgroup 旨在在内存开始不足时回收平板。

Linux cgroup 不会自动虚拟化/proc/meminfo(或 中的任何其他文件/proc),因此会显示整个机器的值。这会使 VPS 客户感到困惑。但是,可以使用命名空间来替换由特定容器软件伪造/proc/meminfo的文件。假值的有用程度取决于该特定软件的作用。

systemd相信 cgroup-v1 不能安全地委托给例如容器。我查看了systemd-nspawn我的 cgroup-v1 系统上的一个容器。我可以看到它被放置在里面的 cgroup,以及内存占用。另一方面,所包含的systemd没有为资源记帐设置通常的每服务 cgroup。如果此 cgroup 中未启用内存记帐,我认为容器将无法启用它。

我假设如果您在 cgroup-v2 容器内,它看起来与真实 cgroup-v2 系统的根不同,并且您将能够看到其顶级 cgroup 的内存占用情况。或者,如果您看到的 cgroup 没有启用内存记帐,希望您将被委派权限,以便您可以systemd(或等效的)中启用内存记帐