【翻译】linux中cgroups内存控制子系统memory.oom_control文件

2022-09-07 10:05:25 浏览数 (1)

翻译自:redhat文档的部分内容。 新linux内核cgroup的memory子系统提供memory.oom_control来开关Cgroup中oom killer,并且提供了消息接口。

memory.oom_control

包含一个标志(0或1)来开启或者关闭cgroup的OOM killer。如果开启(1),任务如果尝试申请内存超过允许,就会被系统OOM killer终止。OOM killer在每个使用cgroup内存子系统中都是默认开启的。如果需要关闭,则可以向memory.oom_control文件写入1.

代码语言:javascript复制
echo 1 > /cgroup/memory/lab1/memory.oom_control

如果OOM killer关闭,那么进程尝试申请的内存超过允许,那么它就会被暂停(就是hang死),直到额外的内存被释放。 memory.oom_control文件也报告当前在under_oom入口下cgroup的OOM状态。如果cgroup内存耗尽,任务被暂停,under_oom条目返回值为1。 Memory.oom_control文件能允许通过notification API发送事件,报告OOM状态。

Example 3.3. OOM Control and Notifications

下面的例子演示了当一个在cgroup中的进程尝试使用超过允许的内存OOM killer进程的行为。以及notification 处理器如何报告OOM状态.

绑定memory子系统到层级,并且创建一个cgroup
代码语言:javascript复制
~]# mount -t cgroup -o memory memory /cgroup/memory
~]# mkdir /cgroup/memory/blue
设置blue cgroup的内存总量限制为100MB
代码语言:javascript复制
~]# echo 104857600 > memory.limit_in_bytes
进入blue目录,并且确认OOM killer开启
代码语言:javascript复制
~]# cd /cgroup/memory/blue
blue]# cat memory.oom_control
oom_kill_disable 0
under_oom 0
移动当前的shell进程到blue组的tasks文件中,这样,所有shell启动的子进程都会自动移入blue组:
代码语言:javascript复制
blue]# echo $$ > tasks
开启测试程序,尝试分配大量内存,超过第二步设置的限制值,很快,blue组耗尽内存,OOM killer终止了test程序,向标准输出报告Killed。
代码语言:javascript复制
blue]# ~/mem-hog
Killed
以下是测试程序的样例:
代码语言:javascript复制
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define KB (1024)
#define MB (1024 * KB)
#define GB (1024 * MB)

int main(int argc, char *argv[])
{
    char *p;

again:
    while ((p = (char *)malloc(GB)))
        memset(p, 0, GB);

    while ((p = (char *)malloc(MB)))
        memset(p, 0, MB);

    while ((p = (char *)malloc(KB)))
        memset(p, 0,KB);

    sleep(1);

    goto again;

    return 0;
}
禁用OOM killer,再次运行测试程序,这次,测试程序被暂停以等待额外的内存释放。
代码语言:javascript复制
blue]# echo 1 > memory.oom_control
blue]# ~/mem-hog
当测试程序被暂停,注意cgroup中under_oom状态发生变化,表名cgroup已经耗尽可用内存:
代码语言:javascript复制
~]# cat /cgroup/memory/blue/memory.oom_control
oom_kill_disable 1
under_oom 1

重新启动OOM killer,立刻终止这个测试程序。

为了接收每个OOM状态通知,创建一个程序作为“使用通知API”的说明。例子:
代码语言:javascript复制
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/eventfd.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
static inline void die(const char *msg)
{
   fprintf(stderr, "error: %s: %s(%d)n", msg, strerror(errno), errno);
   exit(EXIT_FAILURE);
}
static inline void usage(void)
{
    fprintf(stderr, "usage: oom_eventfd_test <cgroup.event_control> <memory.oom_control>n");
    exit(EXIT_FAILURE);
}
#define BUFSIZE 256
int main(int argc, char *argv[])
{
    char buf[BUFSIZE];
    int efd, cfd, ofd, rb, wb;
    uint64_t u;

    if (argc != 3)
        usage();

    if ((efd = eventfd(0, 0)) == -1)
        die("eventfd");

    if ((cfd = open(argv[1], O_WRONLY)) == -1)
        die("cgroup.event_control");

    if ((ofd = open(argv[2], O_RDONLY)) == -1)
        die("memory.oom_control");

    if ((wb = snprintf(buf, BUFSIZE, "%d %d", efd, ofd)) >= BUFSIZE)
        die("buffer too small");

    if (write(cfd, buf, wb) == -1)
        die("write cgroup.event_control");

    if (close(cfd) == -1)
        die("close cgroup.event_control");

    for (;;) {
        if (read(efd, &u, sizeof(uint64_t)) != sizeof(uint64_t))
            die("read eventfd");

        printf("mem_cgroup oom event receivedn");
    }
    return 0;
}

以上程序通过命令行参数指定cgroup,一旦检测到OOM情况,发送“mem_cgroup oom event received”字符串到标准输出。

在一个分开的控制台运行以上通知处理器程序,指定blue层级的控制文件作为参数。
代码语言:javascript复制
~]$ ./oom_notification /cgroup/memory/blue/cgroup.event_control /cgroup/memory/blue/memory.oom_control
在另一个控制台,运行mem_hog测试进程来创建OOM情况,观察oom_notifiction程序在标准输出报告事件。
代码语言:javascript复制
blue]# ~/mem-hog

0 人点赞