将“memfd”视为“拥有该文件的进程”是错误的吗?

将“memfd”视为“拥有该文件的进程”是错误的吗?

https://dvdhrm.wordpress.com/2014/06/10/memfd_create2/

理论上,您可以memfd_create()在不引入新系统调用的情况下实现 [ ] 行为,如下所示:

int fd = open("/tmp", O_RDWR | O_TMPFILE | O_EXCL, S_IRWXU);

(注意,为了更方便地保证这里的 tmpfs,我们可以使用“ /dev/shm”而不是“ /tmp”)。

因此,最重要的问题是为什么我们需要第三条路?

[...]

  • 后备内存由拥有该文件的进程负责,并且不受安装配额的限制。

^ 我认为这句话的第一部分不能可靠,对吗?

memfd_create() 代码实际上是作为“未链接的文件位于 [a] tmpfs 中,该文件必须是内核内部的”。跟踪代码,我了解到它与不实现 LSM 检查不同,并且创建 memfd 是为了支持“密封”,正如博客文章继续解释的那样。但是,我非常怀疑 memfd会计原则上与 tmpfile 不同。

具体来说,当OOM 杀手来敲门,我不认为它会解释 memfds 所持有的内存。这总共可能占 RAM 的 50%——即size= tmpfs 的选项。内核没有为内部 tmpfs 设置不同的值,因此它将使用默认大小 50%。

因此,我认为我们通常可以预期持有较大 memfd 但没有其他重要内存分配的进程不会被 OOM 杀死。那是对的吗?

答案1

基于@danblack 的回答:

该决定基于oom_kill_process()(稍微清理一下):

for_each_thread(p, t) {
        list_for_each_entry(child, &t->children, sibling) {
                unsigned int child_points;

                child_points = oom_badness(child,
                        oc->memcg, oc->nodemask, oc->totalpages);
                if (child_points > victim_points) {
                        put_task_struct(victim);
                        victim = child;
                        victim_points = child_points;
                        get_task_struct(victim);
                }
        }
}

https://github.com/torvalds/linux/blob/master/mm/oom_kill.c#L974

这取决于oom_badness()找到最佳候选人:

child_points = oom_badness(child,
        oc->memcg, oc->nodemask, oc->totalpages);

oom_badness()做:

points = get_mm_rss(p->mm) + get_mm_counter(p->mm, MM_SWAPENTS) +
        mm_pgtables_bytes(p->mm) / PAGE_SIZE;

https://github.com/torvalds/linux/blob/master/mm/oom_kill.c#L233

在哪里:

static inline unsigned long get_mm_rss(struct mm_struct *mm)
{
        return get_mm_counter(mm, MM_FILEPAGES) +
                get_mm_counter(mm, MM_ANONPAGES) +
                get_mm_counter(mm, MM_SHMEMPAGES);
}

https://github.com/torvalds/linux/blob/master/mm/oom_kill.c#L966

所以看起来它计算的是匿名页面,这就是memfd_create()用途。

答案2

是的,您的理解大体上是正确的。系统memfd_create()调用创建一个匿名文件。该文件的行为类似于常规文件,但保留在 RAM 中,不链接到任何特定文件系统[1]。这意味着内存使用直接计入所属进程,就像其他匿名内存分配一样malloc() [2]。因此,当分配不与文件系统或挂载点绑定时,它不会包含在这些级别强制执行的配额中。

OOM 杀手主要根据总体内存消耗及其对系统总内存压力的影响来定位进程,无论其来源如何(例如,临时文件系统,匿名记忆[3]。然而,OOM 杀手确实考虑了总内存使用情况,包括内存映射文件和匿名内存。

当由 所使用的内存memfd_create()占总内存占用量的比重时,当进程持有大量分配memfd_create()并且具有最少的其他内存分配时,它不太可能成为 OOM 杀手的目标,仅仅是因为与不同的进程相比,其总内存使用量仍可能被认为较低。流程。

memfd_create()OOM 杀死中对分配的态度与其他分配的态度显着不同tmpfiles,这是 Linux 作为一个整体如何解释和管理内存的结果,而不是针对不同分配类型的 OOM 杀手的特定机制。[4]

相关内容