翻译自: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:
1 |
~] # echo 1 > /cgroup/memory/lab1/memory.oom_control |
如果OOM killer关闭,那么进程尝试申请的内存超过允许,那么它就会被暂停,直到额外的内存被释放。 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状态。 1. 绑定memory子系统到层级,并且创建一个cgroup;
1 |
~] # mount -t cgroup -o memory memory /cgroup/memory |
2 |
~] # mkdir /cgroup/memory/blue |
2. 设置blue cgroup的内存总量限制为100MB:
1 |
~] # echo 104857600 > memory.limit_in_bytes |
3. 进入blue目录,并且确认OOM killer开启:
1 |
~] # cd /cgroup/memory/blue |
2 |
blue] # cat memory.oom_control |
3 |
oom_kill_disable 0 |
4 |
under_oom 0 |
4. 移动当前的shell进程到blue组的tasks文件中,这样,所有shell启动的子进程都会自动移入blue组:
1 |
blue] # echo $$ > tasks |
5. 开启测试程序,尝试分配大量内存,超过第二步设置的限制值,很快,blue组耗尽内存,OOM killer终止了test程序,向标准输出报告Killed。
1 |
blue] # ~/mem-hog |
2 |
Killed |
以下是测试程序的样例:
01 |
#include |
02 |
#include |
03 |
#include |
04 |
#include |
05 |
06 |
#define KB (1024) |
07 |
#define MB (1024 * KB) |
08 |
#define GB (1024 * MB) |
09 |
10 |
int main( int argc, char *argv[]) |
11 |
{
|
12 |
char *p; |
13 |
again: |
14 |
while ((p = ( char *) malloc (GB))) |
15 |
memset (p, 0, GB); |
16 |
while ((p = ( char *) malloc (MB))) |
17 |
memset (p, 0, MB); |
18 |
19 |
while ((p = ( char *) malloc (KB))) |
20 |
memset (p, 0, KB); |
21 |
sleep(1); |
22 |
goto again; |
23 |
return 0; |
24 |
} |
6. 禁用OOM killer,再次运行测试程序,这次,测试程序被暂停以等待额外的内存释放。
1 |
blue] # echo 1 > memory.oom_control |
2 |
blue] # ~/mem-hog |
7. 当测试程序被暂停,注意cgroup中under_oom状态发生变化,表名cgroup已经耗尽可用内存:
1 |
~] # cat /cgroup/memory/blue/memory.oom_control |
2 |
oom_kill_disable 1 |
3 |
under_oom 1 |
重新启动OOM killer,立刻终止这个测试程序。
8. 为了接收每个OOM状态通知,创建一个程序作为“使用通知API”的说明。例子:
01 |
#include |
02 |
#include |
03 |
#include |
04 |
#include |
05 |
#include |
06 |
#include |
07 |
#include |
08 |
#include |
09 |
10 |
static inline void die( const char *msg) |
11 |
{
|
12 |
fprintf (stderr, "error: %s: %s(%d)\n" , msg, strerror ( errno ), errno ); |
13 |
exit (EXIT_FAILURE); |
14 |
} |
15 |
16 |
static inline void usage( void ) |
17 |
{
|
18 |
fprintf (stderr, "usage: oom_eventfd_test \n" ); |
19 |
exit (EXIT_FAILURE); |
20 |
} |
21 |
22 |
#define BUFSIZE 256 |
23 |
24 |
int main( int argc, char *argv[]) |
25 |
{
|
26 |
char buf[BUFSIZE]; |
27 |
int efd, cfd, ofd, rb, wb; |
28 |
uint64_t u; |
29 |
30 |
if (argc != 3) |
31 |
usage(); |
32 |
33 |
if ((efd = eventfd(0, 0)) == -1) |
34 |
die( "eventfd" ); |
35 |
36 |
if ((cfd = open(argv[1], O_WRONLY)) == -1) |
37 |
die( "cgroup.event_control" ); |
38 |
39 |
if ((ofd = open(argv[2], O_RDONLY)) == -1) |
40 |
die( "memory.oom_control" ); |
41 |
42 |
if ((wb = snprintf(buf, BUFSIZE, "%d %d" , efd, ofd)) >= BUFSIZE) |
43 |
die( "buffer too small" ); |
44 |
45 |
if (write(cfd, buf, wb) == -1) |
46 |
die( "write cgroup.event_control" ); |
47 |
48 |
if (close(cfd) == -1) |
49 |
die( "close cgroup.event_control" ); |
50 |
51 |
for (;;) {
|
52 |
if (read(efd, &u, sizeof (uint64_t)) != sizeof (uint64_t)) |
53 |
die( "read eventfd" ); |
54 |
55 |
printf ( "mem_cgroup oom event received\n" ); |
56 |
} |
57 |
58 |
return 0; |
59 |
} |
以上程序通过命令行参数指定cgroup,一旦检测到OOM情况,发送“mem_cgroup oom event received”字符串到标准输出。
9. 在一个分开的控制台运行以上通知处理器程序,指定blue层级的控制文件作为参数。
1 |
~]$ . /oom_notification /cgroup/memory/blue/cgroup .event_control /cgroup/memory/blue/memory .oom_control |
10. 在另一个控制台,运行mem_hog测试进程来创建OOM情况,观察oom_notifiction程序在标准输出报告事件。
1 |
blue] # ~/mem-hog |
转载请注明:云计算技术手札 » 【翻译】linux中cgroups内存控制子系统memory.oom_control文件