田文军 發表於 2023-7-6 00:00:00

Linux 僵尸进程产生原因及解决方法

<p>
        linux 允许进程查询内核以获得其父进程的 pid,或者其任何子进程的执行状态。例如,进程可以创建一个子进程来执行特定的任务,然后调用诸如 wait() 这样的一些库函数检查子进程是否终止。如果子进程已经终止,那么,它的终止代号将告诉父进程这个任务是否已成功地完成。</p>
<p>
        为了遵循这些设计原则,不允许 linux 内核在进程一终止后就丢弃包含在进程描述符字段中的数据。只有父进程发出了与被终止的进程相关的 wait() 类系统调用之后,才允许这样做。这就是引入僵死状态的原因:尽管从技术上来说进程已死,但必须保存它的描述符,直到父进程得到通知。</p>
<p>
        如果一个进程已经终止,但是它的父进程尚未调用 wait() 或 waitpid() 对它进行清理,这时的进程状态称为僵死状态,处于僵死状态的进程称为僵尸进程(zombie process)。任何进程在刚终止时都是僵尸进程,正常情况下,僵尸进程都立刻被父进程清理了。</p>
<p>
        <strong>僵尸进程是如何产生的</strong></p>
<p>
         在unix 系统中,一个进程结束了,但是他的父进程没有等待(调用wait / waitpid)他,那么他将变成一个僵尸进程。通过ps命令查看其带有defunct的标志。僵尸进程是一个早已死亡的进程,但在进程表 (processs table)中仍占了一个位置(slot)。</p>
<p>
        但是如果该进程的父进程已经先结束了,那么该进程就不会变成僵尸进程。因为每个进程结束的时候,系统都会扫描当前系统中所运行的所有进程,看看有没有哪个 进程是刚刚结束的这个进程的子进程,如果是的话,就由init进程来接管他,成为他的父进程,从而保证每个进程都会有一个父进程。而init进程会自动 wait其子进程,因此被init接管的所有进程都不会变成僵尸进程。</p>
<p>
        为了观察到僵尸进程,我们自己写一个不正常的程序,父进程 fork 出子进程,子进程终止,而父进程既不终止也不调用 wait 清理子进程:</p>
<div class="jb51code">
        <div>
                <div class="syntaxhighlightercpp" id="highlighter_491450">
                        <div class="toolbar">
                                <span>?</span>
</div>
                        <table border="0" cellpadding="0" cellspacing="0"><tbody><tr>
<td class="gutter">
                                                        <div class="line number1 index0 alt2">
                                                                1</div>
                                                        <div class="line number2 index1 alt1">
                                                                2</div>
                                                        <div class="line number3 index2 alt2">
                                                                3</div>
                                                        <div class="line number4 index3 alt1">
                                                                4</div>
                                                        <div class="line number5 index4 alt2">
                                                                5</div>
                                                        <div class="line number6 index5 alt1">
                                                                6</div>
                                                        <div class="line number7 index6 alt2">
                                                                7</div>
                                                        <div class="line number8 index7 alt1">
                                                                8</div>
                                                        <div class="line number9 index8 alt2">
                                                                9</div>
                                                        <div class="line number10 index9 alt1">
                                                                10</div>
                                                        <div class="line number11 index10 alt2">
                                                                11</div>
                                                        <div class="line number12 index11 alt1">
                                                                12</div>
                                                        <div class="line number13 index12 alt2">
                                                                13</div>
                                                        <div class="line number14 index13 alt1">
                                                                14</div>
                                                        <div class="line number15 index14 alt2">
                                                                15</div>
                                                        <div class="line number16 index15 alt1">
                                                                16</div>
                                                        <div class="line number17 index16 alt2">
                                                                17</div>
                                                        <div class="line number18 index17 alt1">
                                                                18</div>
                                                        <div class="line number19 index18 alt2">
                                                                19</div>
                                                        <div class="line number20 index19 alt1">
                                                                20</div>
                                                        <div class="line number21 index20 alt2">
                                                                21</div>
                                                        <div class="line number22 index21 alt1">
                                                                22</div>
                                                        <div class="line number23 index22 alt2">
                                                                23</div>
                                                        <div class="line number24 index23 alt1">
                                                                24</div>
                                                        <div class="line number25 index24 alt2">
                                                                25</div>
                                                        <div class="line number26 index25 alt1">
                                                                26</div>
                                                        <div class="line number27 index26 alt2">
                                                                27</div>
                                                </td>
                                                <td class="code">
                                                        <div class="container">
                                                                <div class="line number1 index0 alt2">
                                                                        <code class="cpp preprocessor">#include &lt;unistd.h&gt;</code>
</div>
                                                                <div class="line number2 index1 alt1">
                                                                        <code class="cpp preprocessor">#include &lt;stdio.h&gt;</code>
</div>
                                                                <div class="line number3 index2 alt2">
                                                                        <code class="cpp preprocessor">#include &lt;stdlib.h&gt;</code>
</div>
                                                                <div class="line number4 index3 alt1">
                                                                         </div>
                                                                <div class="line number5 index4 alt2">
                                                                        <code class="cpp color1 bold">int</code> <code class="cpp plain">main(</code><code class="cpp keyword bold">void</code><code class="cpp plain">)</code>
</div>
                                                                <div class="line number6 index5 alt1">
                                                                        <code class="cpp plain">{</code>
</div>
                                                                <div class="line number7 index6 alt2">
                                                                        <code class="cpp spaces">  </code><code class="cpp color1 bold">int</code> <code class="cpp plain">i = 100;</code>
</div>
                                                                <div class="line number8 index7 alt1">
                                                                        <code class="cpp spaces">  </code><code class="cpp plain">pid_t pid=fork();</code>
</div>
                                                                <div class="line number9 index8 alt2">
                                                                        <code class="cpp spaces">  </code><code class="cpp keyword bold">if</code><code class="cpp plain">(pid &lt; 0)</code>
</div>
                                                                <div class="line number10 index9 alt1">
                                                                        <code class="cpp spaces">  </code><code class="cpp plain">{</code>
</div>
                                                                <div class="line number11 index10 alt2">
                                                                        <code class="cpp spaces">    </code><code class="cpp functions bold">perror</code><code class="cpp plain">(</code><code class="cpp string">"fork failed."</code><code class="cpp plain">);</code>
</div>
                                                                <div class="line number12 index11 alt1">
                                                                        <code class="cpp spaces">    </code><code class="cpp functions bold">exit</code><code class="cpp plain">(1);</code>
</div>
                                                                <div class="line number13 index12 alt2">
                                                                        <code class="cpp spaces">  </code><code class="cpp plain">}</code>
</div>
                                                                <div class="line number14 index13 alt1">
                                                                        <code class="cpp spaces">  </code><code class="cpp keyword bold">if</code><code class="cpp plain">(pid &gt; 0)</code>
</div>
                                                                <div class="line number15 index14 alt2">
                                                                        <code class="cpp spaces">  </code><code class="cpp plain">{</code>
</div>
                                                                <div class="line number16 index15 alt1">
                                                                        <code class="cpp spaces">    </code><code class="cpp functions bold">printf</code><code class="cpp plain">(</code><code class="cpp string">"this is the parent process. my pid is %d.\n"</code><code class="cpp plain">, getpid());</code>
</div>
                                                                <div class="line number17 index16 alt2">
                                                                        <code class="cpp spaces">    </code><code class="cpp keyword bold">for</code><code class="cpp plain">(; i &gt; 0; i--)</code>
</div>
                                                                <div class="line number18 index17 alt1">
                                                                        <code class="cpp spaces">    </code><code class="cpp plain">{</code>
</div>
                                                                <div class="line number19 index18 alt2">
                                                                        <code class="cpp spaces">      </code><code class="cpp plain">sleep(1);</code>
</div>
                                                                <div class="line number20 index19 alt1">
                                                                        <code class="cpp spaces">    </code><code class="cpp plain">}</code>
</div>
                                                                <div class="line number21 index20 alt2">
                                                                        <code class="cpp spaces">  </code><code class="cpp plain">}</code>
</div>
                                                                <div class="line number22 index21 alt1">
                                                                        <code class="cpp spaces">  </code><code class="cpp keyword bold">else</code> <code class="cpp keyword bold">if</code><code class="cpp plain">(pid == 0)</code>
</div>
                                                                <div class="line number23 index22 alt2">
                                                                        <code class="cpp spaces">  </code><code class="cpp plain">{</code>
</div>
                                                                <div class="line number24 index23 alt1">
                                                                        <code class="cpp spaces">    </code><code class="cpp functions bold">printf</code><code class="cpp plain">(</code><code class="cpp string">"this is the child process. my pid is: %d. my ppid is: %d.\n"</code><code class="cpp plain">, getpid(), getppid());</code>
</div>
                                                                <div class="line number25 index24 alt2">
                                                                        <code class="cpp spaces">  </code><code class="cpp plain">}</code>
</div>
                                                                <div class="line number26 index25 alt1">
                                                                        <code class="cpp spaces">  </code><code class="cpp keyword bold">return</code> <code class="cpp plain">0;</code>
</div>
                                                                <div class="line number27 index26 alt2">
                                                                        <code class="cpp plain">}</code>
</div>
                                                        </div>
                                                </td>
                                        </tr></tbody></table>
</div>
        </div>
</div>
<p>
        把上面的代码保存到文件 zomprocdemo.c 文件中,并执行下面的命令编译:</p>
<div class="jb51code">
        <div>
                <div class="syntaxhighlightercpp" id="highlighter_378388">
                        <div class="toolbar">
                                <span>?</span>
</div>
                        <table border="0" cellpadding="0" cellspacing="0"><tbody><tr>
<td class="gutter">
                                                        <div class="line number1 index0 alt2">
                                                                1</div>
                                                </td>
                                                <td class="code">
                                                        <div class="container">
                                                                <div class="line number1 index0 alt2">
                                                                        <code class="cpp plain">$ gcc zomprocdemo.c -o zomprocdemo</code>
</div>
                                                        </div>
                                                </td>
                                        </tr></tbody></table>
</div>
        </div>
</div>
<p>
        然后运行编译出来的 zomprocdemo 程序:</p>
<div class="jb51code">
        <div>
                <div class="syntaxhighlightercpp" id="highlighter_34943">
                        <div class="toolbar">
                                <span>?</span>
</div>
                        <table border="0" cellpadding="0" cellspacing="0"><tbody><tr>
<td class="gutter">
                                                        <div class="line number1 index0 alt2">
                                                                1</div>
                                                </td>
                                                <td class="code">
                                                        <div class="container">
                                                                <div class="line number1 index0 alt2">
                                                                        <code class="cpp plain">$ ./zomprocdemo</code>
</div>
                                                        </div>
                                                </td>
                                        </tr></tbody></table>
</div>
        </div>
</div>
<p>
        <img title="Linux 僵尸进程产生原因及解决方法" alt="Linux 僵尸进程产生原因及解决方法" src="https://zhuji.jb51.net/uploads/img/202305/2f4e96ba24e072d14bd23426cff95994.jpg"></p>
<p>
        此时子进程已经退出,但是父进程没有退出也没有通过 wait() 调用处理子进程。我们使用 ps 命令查看进程的状态:</p>
<p>
        <img title="Linux 僵尸进程产生原因及解决方法" alt="Linux 僵尸进程产生原因及解决方法" src="https://zhuji.jb51.net/uploads/img/202305/7df9ab86130db6a887afc62451030d91.jpg"></p>
<p>
        上图红框中的大写字母 "z" 说明 pid 为 112712 的进程此时处于僵死的状态。</p>
<p>
        让我们接着往下看!在结束 sleep 后父进程退出。当父进程退出后,子进程会变成孤儿进程,此时它会被一个管理进程收养。在不同的系统中,这个管理进程不太一样,早期一般是 init 进程,ubuntu 上是 upstart,还有近来的 systemd。但是它们都完成相同的任务,就是 wiat() 这些孤儿进程,并最终释放它们占用的系统进程表中的资源。这样,这些已经僵死的孤儿进程就彻底的被清除了。</p>
<p>
        <strong>僵尸进程的危害</strong></p>
<p>
        在进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存等。但是仍然为其保留一定的信息(包括进程号 pid,退出状态 the termination status of the process,运行时间 the amount of cpu time taken by the process 等)。直到父进程通过 wait / waitpid 来取时才释放。</p>
<p>
        如果进程不调用 wait / waitpid 的话, 那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程。</p>
<p>
        <strong>如何处理僵尸进程</strong></p>
<p>
        僵尸进程的产生是因为父进程没有 wait() 子进程。所以如果我们自己写程序的话一定要在父进程中通过 wait() 来避免僵尸进程的产生。</p>
<p>
        当系统中出现了僵尸进程时,我们是无法通过 kill 命令把它清除掉的。但是我们可以杀死它的父进程,让它变成孤儿进程,并进一步被系统中管理孤儿进程的进程收养并清理。</p>
<p>
        下面的 demo 中,父进程通过 wait() 等待子进程结束:</p>
<div class="jb51code">
        <div>
                <div class="syntaxhighlightercpp" id="highlighter_964782">
                        <div class="toolbar">
                                <span>?</span>
</div>
                        <table border="0" cellpadding="0" cellspacing="0"><tbody><tr>
<td class="gutter">
                                                        <div class="line number1 index0 alt2">
                                                                1</div>
                                                        <div class="line number2 index1 alt1">
                                                                2</div>
                                                        <div class="line number3 index2 alt2">
                                                                3</div>
                                                        <div class="line number4 index3 alt1">
                                                                4</div>
                                                        <div class="line number5 index4 alt2">
                                                                5</div>
                                                        <div class="line number6 index5 alt1">
                                                                6</div>
                                                        <div class="line number7 index6 alt2">
                                                                7</div>
                                                        <div class="line number8 index7 alt1">
                                                                8</div>
                                                        <div class="line number9 index8 alt2">
                                                                9</div>
                                                        <div class="line number10 index9 alt1">
                                                                10</div>
                                                        <div class="line number11 index10 alt2">
                                                                11</div>
                                                        <div class="line number12 index11 alt1">
                                                                12</div>
                                                        <div class="line number13 index12 alt2">
                                                                13</div>
                                                        <div class="line number14 index13 alt1">
                                                                14</div>
                                                        <div class="line number15 index14 alt2">
                                                                15</div>
                                                        <div class="line number16 index15 alt1">
                                                                16</div>
                                                        <div class="line number17 index16 alt2">
                                                                17</div>
                                                        <div class="line number18 index17 alt1">
                                                                18</div>
                                                        <div class="line number19 index18 alt2">
                                                                19</div>
                                                        <div class="line number20 index19 alt1">
                                                                20</div>
                                                        <div class="line number21 index20 alt2">
                                                                21</div>
                                                        <div class="line number22 index21 alt1">
                                                                22</div>
                                                        <div class="line number23 index22 alt2">
                                                                23</div>
                                                        <div class="line number24 index23 alt1">
                                                                24</div>
                                                        <div class="line number25 index24 alt2">
                                                                25</div>
                                                        <div class="line number26 index25 alt1">
                                                                26</div>
                                                        <div class="line number27 index26 alt2">
                                                                27</div>
                                                        <div class="line number28 index27 alt1">
                                                                28</div>
                                                        <div class="line number29 index28 alt2">
                                                                29</div>
                                                        <div class="line number30 index29 alt1">
                                                                30</div>
                                                        <div class="line number31 index30 alt2">
                                                                31</div>
                                                        <div class="line number32 index31 alt1">
                                                                32</div>
                                                        <div class="line number33 index32 alt2">
                                                                33</div>
                                                        <div class="line number34 index33 alt1">
                                                                34</div>
                                                        <div class="line number35 index34 alt2">
                                                                35</div>
                                                        <div class="line number36 index35 alt1">
                                                                36</div>
                                                </td>
                                                <td class="code">
                                                        <div class="container">
                                                                <div class="line number1 index0 alt2">
                                                                        <code class="cpp preprocessor">#include &lt;sys/types.h&gt;</code>
</div>
                                                                <div class="line number2 index1 alt1">
                                                                        <code class="cpp preprocessor">#include &lt;sys/wait.h&gt;</code>
</div>
                                                                <div class="line number3 index2 alt2">
                                                                        <code class="cpp preprocessor">#include &lt;unistd.h&gt;</code>
</div>
                                                                <div class="line number4 index3 alt1">
                                                                        <code class="cpp preprocessor">#include &lt;stdio.h&gt;</code>
</div>
                                                                <div class="line number5 index4 alt2">
                                                                        <code class="cpp preprocessor">#include &lt;stdlib.h&gt;</code>
</div>
                                                                <div class="line number6 index5 alt1">
                                                                         </div>
                                                                <div class="line number7 index6 alt2">
                                                                        <code class="cpp color1 bold">int</code> <code class="cpp plain">main(</code><code class="cpp keyword bold">void</code><code class="cpp plain">)</code>
</div>
                                                                <div class="line number8 index7 alt1">
                                                                        <code class="cpp plain">{</code>
</div>
                                                                <div class="line number9 index8 alt2">
                                                                        <code class="cpp spaces">  </code><code class="cpp plain">pid_t pid;</code>
</div>
                                                                <div class="line number10 index9 alt1">
                                                                        <code class="cpp spaces">  </code><code class="cpp plain">pid = fork();</code>
</div>
                                                                <div class="line number11 index10 alt2">
                                                                        <code class="cpp spaces">  </code><code class="cpp keyword bold">if</code> <code class="cpp plain">(pid &lt; 0)</code>
</div>
                                                                <div class="line number12 index11 alt1">
                                                                        <code class="cpp spaces">  </code><code class="cpp plain">{</code>
</div>
                                                                <div class="line number13 index12 alt2">
                                                                        <code class="cpp spaces">    </code><code class="cpp functions bold">perror</code><code class="cpp plain">(</code><code class="cpp string">"fork failed"</code><code class="cpp plain">);</code>
</div>
                                                                <div class="line number14 index13 alt1">
                                                                        <code class="cpp spaces">    </code><code class="cpp functions bold">exit</code><code class="cpp plain">(1);</code>
</div>
                                                                <div class="line number15 index14 alt2">
                                                                        <code class="cpp spaces">  </code><code class="cpp plain">}</code>
</div>
                                                                <div class="line number16 index15 alt1">
                                                                        <code class="cpp spaces">  </code><code class="cpp keyword bold">if</code> <code class="cpp plain">(pid == 0) {</code>
</div>
                                                                <div class="line number17 index16 alt2">
                                                                        <code class="cpp spaces">    </code><code class="cpp color1 bold">int</code> <code class="cpp plain">i;</code>
</div>
                                                                <div class="line number18 index17 alt1">
                                                                        <code class="cpp spaces">     </code><code class="cpp keyword bold">for</code> <code class="cpp plain">(i = 3; i &gt; 0; i--)</code>
</div>
                                                                <div class="line number19 index18 alt2">
                                                                        <code class="cpp spaces">     </code><code class="cpp plain">{</code>
</div>
                                                                <div class="line number20 index19 alt1">
                                                                        <code class="cpp spaces">      </code><code class="cpp functions bold">printf</code><code class="cpp plain">(</code><code class="cpp string">"this is the child\n"</code><code class="cpp plain">);</code>
</div>
                                                                <div class="line number21 index20 alt2">
                                                                        <code class="cpp spaces">      </code><code class="cpp plain">sleep(1);</code>
</div>
                                                                <div class="line number22 index21 alt1">
                                                                        <code class="cpp spaces">     </code><code class="cpp plain">}</code>
</div>
                                                                <div class="line number23 index22 alt2">
                                                                        <code class="cpp spaces">     </code><code class="cpp comments">// exit with code 3 for test.</code>
</div>
                                                                <div class="line number24 index23 alt1">
                                                                        <code class="cpp spaces">    </code><code class="cpp functions bold">exit</code><code class="cpp plain">(3);</code>
</div>
                                                                <div class="line number25 index24 alt2">
                                                                        <code class="cpp spaces">  </code><code class="cpp plain">}</code>
</div>
                                                                <div class="line number26 index25 alt1">
                                                                        <code class="cpp spaces">  </code><code class="cpp keyword bold">else</code>
</div>
                                                                <div class="line number27 index26 alt2">
                                                                        <code class="cpp spaces">  </code><code class="cpp plain">{</code>
</div>
                                                                <div class="line number28 index27 alt1">
                                                                        <code class="cpp spaces">    </code><code class="cpp color1 bold">int</code> <code class="cpp plain">stat_val;</code>
</div>
                                                                <div class="line number29 index28 alt2">
                                                                        <code class="cpp spaces">    </code><code class="cpp plain">wait(&amp;stat_val);</code>
</div>
                                                                <div class="line number30 index29 alt1">
                                                                        <code class="cpp spaces">     </code><code class="cpp keyword bold">if</code> <code class="cpp plain">(wifexited(stat_val))</code>
</div>
                                                                <div class="line number31 index30 alt2">
                                                                        <code class="cpp spaces">     </code><code class="cpp plain">{</code>
</div>
                                                                <div class="line number32 index31 alt1">
                                                                        <code class="cpp spaces">       </code><code class="cpp functions bold">printf</code><code class="cpp plain">(</code><code class="cpp string">"child exited with code %d\n"</code><code class="cpp plain">, wexitstatus(stat_val));</code>
</div>
                                                                <div class="line number33 index32 alt2">
                                                                        <code class="cpp spaces">     </code><code class="cpp plain">}      </code>
</div>
                                                                <div class="line number34 index33 alt1">
                                                                        <code class="cpp spaces">  </code><code class="cpp plain">}</code>
</div>
                                                                <div class="line number35 index34 alt2">
                                                                        <code class="cpp spaces">  </code><code class="cpp keyword bold">return</code> <code class="cpp plain">0;</code>
</div>
                                                                <div class="line number36 index35 alt1">
                                                                        <code class="cpp plain">}</code>
</div>
                                                        </div>
                                                </td>
                                        </tr></tbody></table>
</div>
        </div>
</div>
<p>
        demo 中父进程不仅等待子进程结束,还通过 wexitstatus 宏取到了子进程的 exit code。</p>
<p>
        以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。</p>
<p>
        原文链接:http://www.cnblogs.com/sparkdev/p/8275221.html</p>
頁: [1]
查看完整版本: Linux 僵尸进程产生原因及解决方法