Linux内核-页面缓存、结构地址空间和内存控制组之间的关系是什么?

5
我希望理解 Linux 页面缓存和它与内存 cgroup(v2)的关系。我知道在 cgroups v1 中,内存 cgroups 可以被 隔离并拥有独立的 LRU 列表(我假设 cgroups v2 也是如此)。这一事实以及 mm/vmscan.c 中对 mem_cgroups 的许多引用和 一个名为 shrink_node_memcgs 的函数 让我想到每个 cgroup 都有自己的页面缓存。 这个假设正确吗? 页面缓存中的所有页面是否属于单个 cgroup?
如果这是正确的,我知道页面缓存由 struct address_space 表示(这里)。如何找出给定的 struct address_space 关联哪个 cgroup?我是否需要只查找第一个页面并从页面中找到 cgroup?
1个回答

6
经过大量调查,我对原有的理解存在几个问题。
首先,页面缓存是驻留在内存中的非连续页面集合。很容易陷入认为“页面缓存”是单个连续的内存块/页面(类似于硬件缓存)的陷阱,但实际上,页面缓存只是内存中某些页面的集合,可供将来访问使用。
这些“页面缓存”中的页面甚至没有虚拟地存储在一起。也就是说,内核不会将所有页面缓存中的页面保存在一个全局结构或列表中。相反,更好的思考方式是,页面缓存实际上是内核中所有LRU列表的并集。

这一点以及mm/vmscan.c有很多关于mem_cgroups的引用,并且有一个名为shrink_node_memcgs的函数,使我认为每个cgroup都有自己的页面缓存。

如上所述,每个cgroup都有自己的LRU列表。然而,每个cgroup并没有自己的页面缓存。但是,如果你汇总所有cgroup的LRU列表,你将持有页面缓存的所有页面。
我知道页面缓存是由结构体address_space表示的。
这是不正确的。一个struct address_space确实代表了页面缓存中的一些页面,但它本身并不代表整个页面缓存。实际上,struct address_space表示单个inode(文件)或块设备中缓存的页面(请参见address_space结构中的host成员)。事实上,原始帖子中其中之一的链接引用了这句话:“struct address_space的一个更好的名称可能是page_cache_entityphysical_pages_of_a_file。”(第16章,第327页
您如何找出与给定的struct address_space相关联的cgroup?
由于address_space对应于单个inode(文件),而不是单个cgroup,因此并非所有在此结构中的页面都归入同一cgroup,并且因此驻留在相同的cgroup LRU列表上。例如,想象一下,cgroup 1中的一个进程读取大文件的开头,但是cgroup 2中的另一个进程读取该文件的结尾。每个进程访问的页面来自相同的inode和struct address_space,但其中一些页面将位于cgroup 1的LRU列表中,而其他页面将位于cgroup 2的LRU列表中。
因此,无法从struct address_space中找到cgroup。相反,在理论上,您可以遍历struct address_space页面,然后找到与每个单独页面对应的cgroup(page->mem_cgroup->css.cgroup)。

请注意,一个页面可能被分配给一个cgroup,但仍然可以被不同cgroup中的另一个进程共享/访问。有关为共享内存收费的规则,请参见v1版本(第2.3节)和v2版本("内存所有权")。

补充:

在我的研究中,我遇到了这篇文章,它增加了我的困惑并让我认为address_space与单个cgroup相关联。图4.2似乎表明address_space被嵌套在mm_struct中;由于mm_struct特定于进程,因此这个address_space也应该对应于一个进程,并且通过推广,对应于该进程的cgroup。实际上,这个mm_struct对应的进程持有一个文件描述符(由struct file表示)和这个文件描述符导致文件inode及其相应的address_space。需要这个address_space才能在“页面缓存”中找到来自该文件的特定页面。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接