天天看点

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

新linux内核cgroup的memory子系统提供memory.oom_control来开关cgroup中oom killer,并且提供了消息接口。

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

<code>1</code>

<code>~]</code><code># echo 1 &gt; /cgroup/memory/lab1/memory.oom_control</code>

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

下面的例子演示了当一个在cgroup中的进程尝试使用超过允许的内存oom killer进程的行为。以及notification 处理器如何报告oom状态。 1. 绑定memory子系统到层级,并且创建一个cgroup;

<code>~]</code><code># mount -t cgroup -o memory memory /cgroup/memory</code>

<code>2</code>

<code>~]</code><code># mkdir /cgroup/memory/blue</code>

2. 设置blue cgroup的内存总量限制为100mb:

<code>~]</code><code># echo 104857600 &gt; memory.limit_in_bytes</code>

3. 进入blue目录,并且确认oom killer开启:

<code>~]</code><code># cd /cgroup/memory/blue</code>

<code>blue]</code><code># cat memory.oom_control</code>

<code>3</code>

<code>oom_kill_disable 0</code>

<code>4</code>

<code>under_oom 0</code>

4. 移动当前的shell进程到blue组的tasks文件中,这样,所有shell启动的子进程都会自动移入blue组:

<code>blue]</code><code># echo $$ &gt; tasks</code>

5. 开启测试程序,尝试分配大量内存,超过第二步设置的限制值,很快,blue组耗尽内存,oom killer终止了test程序,向标准输出报告killed。

<code>blue]</code><code># ~/mem-hog</code>

<code>killed</code>

以下是测试程序的样例:

<code>01</code>

<code>#include</code>

<code>02</code>

<code>03</code>

<code>04</code>

<code>05</code>

<code>06</code>

<code>#define kb (1024)</code>

<code>07</code>

<code>#define mb (1024 * kb)</code>

<code>08</code>

<code>#define gb (1024 * mb)</code>

<code>09</code>

<code>10</code>

<code>int</code> <code>main(</code><code>int</code> <code>argc,</code><code>char</code> <code>*argv[])</code>

<code>11</code>

<code>{</code>

<code>12</code>

<code>char</code> <code>*p;</code>

<code>13</code>

<code>again:</code>

<code>14</code>

<code>while</code> <code>((p = (</code><code>char</code> <code>*)</code><code>malloc</code><code>(gb)))</code>

<code>15</code>

<code>memset</code><code>(p, 0, gb);</code>

<code>16</code>

<code>while</code> <code>((p = (</code><code>char</code> <code>*)</code><code>malloc</code><code>(mb)))</code>

<code>17</code>

<code>memset</code><code>(p, 0, mb);</code>

<code>18</code>

<code>19</code>

<code>while</code> <code>((p = (</code><code>char</code> <code>*)</code><code>malloc</code><code>(kb)))</code>

<code>20</code>

<code>memset</code><code>(p, 0, kb);</code>

<code>21</code>

<code>sleep(1);</code>

<code>22</code>

<code>goto</code> <code>again;</code>

<code>23</code>

<code>return</code> <code>0;</code>

<code>24</code>

<code>}</code>

6. 禁用oom killer,再次运行测试程序,这次,测试程序被暂停以等待额外的内存释放。

<code>blue]</code><code># echo 1 &gt; memory.oom_control</code>

7. 当测试程序被暂停,注意cgroup中under_oom状态发生变化,表名cgroup已经耗尽可用内存:

<code>~]</code><code># cat /cgroup/memory/blue/memory.oom_control</code>

<code>oom_kill_disable 1</code>

<code>under_oom 1</code>

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

8. 为了接收每个oom状态通知,创建一个程序作为“使用通知api”的说明。例子:

<code>static</code> <code>inline</code> <code>void</code> <code>die(</code><code>const</code> <code>char</code> <code>*msg)</code>

<code>fprintf</code><code>(stderr,</code><code>"error: %s: %s(%d)\n"</code><code>, msg,</code><code>strerror</code><code>(</code><code>errno</code><code>),</code><code>errno</code><code>);</code>

<code>exit</code><code>(exit_failure);</code>

<code>static</code> <code>inline</code> <code>void</code> <code>usage(</code><code>void</code><code>)</code>

<code>fprintf</code><code>(stderr,</code><code>"usage: oom_eventfd_test \n"</code><code>);</code>

<code>#define bufsize 256</code>

<code>25</code>

<code>26</code>

<code>char</code> <code>buf[bufsize];</code>

<code>27</code>

<code>int</code> <code>efd, cfd, ofd, rb, wb;</code>

<code>28</code>

<code>uint64_t u;</code>

<code>29</code>

<code>30</code>

<code>if</code> <code>(argc != 3)</code>

<code>31</code>

<code>usage();</code>

<code>32</code>

<code>33</code>

<code>if</code> <code>((efd = eventfd(0, 0)) == -1)</code>

<code>34</code>

<code>die(</code><code>"eventfd"</code><code>);</code>

<code>35</code>

<code>36</code>

<code>if</code> <code>((cfd = open(argv[1], o_wronly)) == -1)</code>

<code>37</code>

<code>die(</code><code>"cgroup.event_control"</code><code>);</code>

<code>38</code>

<code>39</code>

<code>if</code> <code>((ofd = open(argv[2], o_rdonly)) == -1)</code>

<code>40</code>

<code>die(</code><code>"memory.oom_control"</code><code>);</code>

<code>41</code>

<code>42</code>

<code>if</code> <code>((wb = snprintf(buf, bufsize,</code><code>"%d %d"</code><code>, efd, ofd)) &gt;= bufsize)</code>

<code>43</code>

<code>die(</code><code>"buffer too small"</code><code>);</code>

<code>44</code>

<code>45</code>

<code>if</code> <code>(write(cfd, buf, wb) == -1)</code>

<code>46</code>

<code>die(</code><code>"write cgroup.event_control"</code><code>);</code>

<code>47</code>

<code>48</code>

<code>if</code> <code>(close(cfd) == -1)</code>

<code>49</code>

<code>die(</code><code>"close cgroup.event_control"</code><code>);</code>

<code>50</code>

<code>51</code>

<code>for</code> <code>(;;) {</code>

<code>52</code>

<code>if</code> <code>(read(efd, &amp;u,</code><code>sizeof</code><code>(uint64_t)) !=</code><code>sizeof</code><code>(uint64_t))</code>

<code>53</code>

<code>die(</code><code>"read eventfd"</code><code>);</code>

<code>54</code>

<code>55</code>

<code>printf</code><code>(</code><code>"mem_cgroup oom event received\n"</code><code>);</code>

<code>56</code>

<code>57</code>

<code>58</code>

<code>59</code>

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

9. 在一个分开的控制台运行以上通知处理器程序,指定blue层级的控制文件作为参数。

<code>~]$ .</code><code>/oom_notification</code><code>/cgroup/memory/blue/cgroup</code><code>.event_control</code><code>/cgroup/memory/blue/memory</code><code>.oom_control</code>

10. 在另一个控制台,运行mem_hog测试进程来创建oom情况,观察oom_notifiction程序在标准输出报告事件。