Linux 内核 - 页缓存、结构地址空间和内存 cgroup 之间有什么关系?

wxz*_*wxz 6 linux operating-system memory-management linux-kernel cgroups

我试图了解 Linux 页面缓存以及它与内存 cgroup (v2) 的关系。我知道使用 cgroupsv1,内存 cgroup 可以被隔离并具有独立的 LRU 列表(我假设 cgroupsv2 是相同的)。这个事实以及mm/vmscan.c有很多引用mem_cgroups并且有一个名为 的函数的shrink_node_memcgs事实,让我认为每个 cgroup 都有自己的页面缓存。这个假设是真的吗?页面缓存中的所有页面都属于一个 cgroup 吗?

struct address_space如果这是真的,我知道页面缓存由(此处)表示。如何找出与给定的 cgroup 关联的内容struct address_space?我是否必须只找到其中​​的第一页,struct address_space然后从该页面中找到 cgroup?

wxz*_*wxz 7

经过大量调查,我原来的理解存在几个问题。

首先,页缓存是驻留在内存中的非连续页的集合。人们很容易陷入将“页面缓存”视为单个连续的内存块/页面(类似于硬件缓存)的陷阱,但页面缓存只是内存中可用的一些页面的集合以供将来访问。

“页面缓存”中的这些页面甚至没有虚拟地存储在一起。如图所示,内核不会将页面缓存中的所有页面保存在一个全局结构或列表中。相反,更好的思考方式是页面缓存实际上是内核中所有 LRU 列表的并集。

这个事实以及 mm/vmscan.c 有很多对 mem_cgroups 的引用,并且有一个名为 Shrink_node_memcgs 的函数,让我认为每个 cgroup 都有自己的页面缓存。

如前所述,每个 cgroup 都有自己的 LRU 列表。然而,每个 cgroup 没有自己的页面缓存。但如果您整理所有 cgroup 中的所有 LRU,您将保存页面缓存的所有页面。

我知道页面缓存由 struct address_space 表示

这是不正确的。Astruct address_space确实代表页面缓存中的一些页面,但它本身并不代表整个页面缓存。struct address_space实际上代表来自单个inode(文件)或块设备的缓存页面(请参阅结构中的host 成员address_space)。事实上,原始帖子中的一个链接引用了这样的话:“[for struct address_space] 的更好名称可能是page_cache_entityphysical_pages_of_a_file。” (第 327 页,第 16 章)

如何找出与给定 struct address_space 关联的 cgroup?

由于 anaddress_space对应于单个inode(文件)而不是单个 cgroup,因此该结构中的所有页面都不会被分配到同一 cgroup,因此不会驻留在同一 cgroup LRU 列表中。例如,假设 cgroup 1 中的一个进程读取一个大文件的开头,但 cgroup 2 中的另一个进程读取该文件的结尾。每个进程访问的页面都来自相同的inodestruct address_space,但其中一些页面将位于 cgroup 1 的 LRU 列表中,而其他页面将位于 cgroup 2 的 LRU 列表中。

所以不可能从 a 中找到 cgroup struct address_space。相反,理论上,您可以遍历页面struct address_space,然后找到与每个单独页面 ( ) 对应的 cgroup page->mem_cgroup->css.cgroup

请记住,属于一个 cgroup 的页面仍可能被不同 cgroup 中的另一个进程共享/访问。有关 v1 的 cgroup 共享内存收费的规则(第 2.3 节)请参阅此处,v2 的规则请参阅此处(“内存所有权”)。

附录:

在我的研究过程中,我遇到了这篇文章,它让我感到困惑,并让我认为 anaddress_space与单个 cgroup 相关联。图 4.2 让它看起来像是address_space被埋在mm_struct;中。由于mm_struct它特定于一个进程,那么它address_space也应该对应于一个进程,并且通过扩展,该进程的 cgroup。实际上,它mm_struct对应的进程持有struct file一个文件的文件描述符(用 表示),并且该文件描述符指向该文件inode及其对应的address_space. 这address_space是为了在“页面缓存”中专门从该文件中查找页面所必需的。