", donc les processus zombies sont générés ; si un grand nombre de processus zombies sont générés, le système ne pourra pas générer de nouveaux processus car il n'y a pas de numéros de processus disponibles, les processus zombies doivent donc être évités."/> ", donc les processus zombies sont générés ; si un grand nombre de processus zombies sont générés, le système ne pourra pas générer de nouveaux processus car il n'y a pas de numéros de processus disponibles, les processus zombies doivent donc être évités.">
Maison > Article > Opération et maintenance > Qu'est-ce qu'un processus zombie Linux ?
Le processus zombie Linux est un processus qui est mort depuis longtemps, mais il occupe toujours une position dans la table des processus ; si le processus parent n'a pas wait() lorsque le processus enfant meurt, vous pouvez généralement le voir affiché comme "
" en utilisant ps, comme ceci, des processus zombies sont générés ; si un grand nombre de processus zombies sont générés, le système ne pourra pas générer de nouveaux processus car il n'y a pas de numéros de processus disponibles, les processus zombies doivent donc être évités.
L'environnement d'exploitation de ce tutoriel : système Linux5.9.8, ordinateur Dell G3.
La génération et l'évitement des processus zombies (processus défunts) sous Linux
Dans un système UNIX, un processus se termine, mais son processus parent ne l'attend pas (appel wait/waitpid). ), alors cela deviendra un processus zombie. Lorsque vous utilisez la commande ps pour observer l'état d'exécution du processus, vous verrez que la barre d'état de ces processus est obsolète. Un processus zombie est un processus mort depuis longtemps, mais qui occupe toujours un emplacement dans la table des processus.
Mais si le processus parent du processus s'est terminé en premier, alors le processus ne deviendra pas un processus zombie. Parce que lorsque chaque processus se termine, le système analysera tous les processus en cours d'exécution dans le système actuel pour voir si un processus est un processus enfant du processus qui vient de se terminer. Si tel est le cas, le processus Init le prendra en charge et en deviendra le processus parent. garantissant ainsi que chaque processus aura un processus parent. Le processus Init attendra automatiquement ses processus enfants, de sorte que tous les processus repris par Init ne deviendront pas des processus zombies.
Chaque processus Unix a un point d'entrée (entrée) dans la table des processus Processus principalToutes les informations utilisées lors de l'exécution du processus sont stockées au point d'entrée. Lorsque vous utilisez la commande ps pour afficher les informations de processus dans le système, vous voyez les données pertinentes dans la table de processus. Lorsqu'un nouveau processus est créé avec l'appel système fork(), le processus principal attribuera un point d'entrée au nouveau processus dans la table des processus, puis stockera les informations pertinentes dans la table des processus correspondant au point d'entrée. L'une de ces informations est le numéro d'identification de son processus parent.
La fin du processus enfant et l'exécution du processus parent sont un processus asynchrone, c'est-à-dire que le processus parent ne peut jamais prédire quand le processus enfant se terminera. Ainsi, les informations d'état à la fin du processus enfant seront-elles perdues parce que le processus parent est trop occupé pour attendre le processus enfant, ou parce qu'il ne sait pas quand le processus enfant se terminera ?
Non. Étant donné qu'UNIX fournit un mécanisme garantissant que tant que le processus parent souhaite connaître les informations d'état à la fin du processus enfant, il peut les obtenir. Ce mécanisme est le suivant : lorsque le processus enfant termine son cycle de vie, il exécutera l'appel système exit() et le noyau libère toutes les ressources du processus, y compris les fichiers ouverts, la mémoire occupée, etc. Cependant, certaines informations sont toujours conservées pour celui-ci (notamment l'ID du processus, le code de sortie, l'état de fin du processus, la quantité de temps CPU pris par le processus, etc.), et ces données seront conservées jusqu'à ce que le système passe à son processus parent et ne le libérez pas jusqu'à ce que le processus parent le récupère via wait/waitpid.
En d’autres termes, lorsqu’un processus meurt, il ne disparaît pas complètement. Le processus se termine, il n'est plus en cours d'exécution, mais il reste encore des données résiduelles en attente que le processus parent les récupère. Lorsqu'un processus parent forke() un processus enfant, il doit utiliser wait() (ou waitpid()) pour attendre la fin du processus enfant. C'est cette action wait() qui fait disparaître les données résiduelles du processus enfant.
Si le processus parent n'appelle pas wait/waitpid, les informations conservées ne seront pas libérées et son numéro de processus sera toujours occupé, mais la capacité de la table de processus du système est limitée. les nombres pouvant être utilisés sont également limités. Si un grand nombre de processus zombies sont générés, le système ne pourra pas générer de nouveaux processus car aucun numéro de processus n'est disponible.
Ainsi, les processus défunts occupent non seulement les ressources mémoire du système et affectent les performances du système, mais s'ils sont trop nombreux, ils peuvent également provoquer une paralysie du système. De plus, étant donné que le planificateur ne peut pas sélectionner le processus défunt, la commande kill ne peut pas être utilisée pour supprimer le processus défunt. Le seul moyen est de redémarrer le système.
Si le processus parent n'attend pas() lorsque le processus enfant meurt, vous pouvez généralement utiliser ps pour voir qu'il est affiché comme "21eba13340b1d3a525d7480ca5bbd370", ainsi un processus zombie est généré. . Cela restera ainsi pour toujours jusqu'à ce que le processus parent wait().
On peut voir que le processus défunt apparaît après la fin du processus enfant, mais avant que le processus parent n'ait lu les données. En profitant de cela, nous pouvons créer un processus défunt en utilisant le programme suivant :
#include ade979de5fc0e1ca0540f360a64c230b
#includeda996ff59ef1c1fa2f19eea6833e0f6c
main()
{
if(!fork())
{
printf(“child pid=%d\n”, getpid());
exit(0);
}
sleep(20);
printf(“parent pid=%d \n”, getpid());
exit(0);
}
当上述程序以后台的方式执行时,第17行强迫程序睡眠20秒,让用户有时间输入ps -e指令,观察进程的状态,我们看到进程表中出现了defunct进程。当父进程执行终止后,再用ps -e命令观察时,我们会发现defunct进程也随之消失。这是因为父进程终止后,init 进程会接管父进程留下的这些“孤儿进程”(orphan process),而这些“孤儿进程”执行完后,它在进程表中的进入点将被删除。如果一个程序设计上有缺陷,就可能导致某个进程的父进程一直处于睡眠状态或是陷入死循环,父进程没有wait子进程,也没有终止以使Init接管,该子进程执行结束后就变成了defunct进程,这个defunct 进程可能会一直留在系统中直到系统重新启动。
在看一个产生僵尸进程的例子。
子进程要执行的程序test_prog
//test.c
#include ade979de5fc0e1ca0540f360a64c230b int main() {
int i = 0;
for (i = 0 ; i < 10; i++)
{
printf ("child time %d\n", i+1);
sleep (1);
}
return 0; }
父进程father的代码father.c
#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> int main() { int pid = fork (); if (pid == 0) { system ("./test_prog"); _exit (0); }else { int i = 0; /* int status = 0; while (!waitpid(pid, &status, WNOHANG)) { printf ("father waiting%d\n", ++i); sleep (1); }*/ while (1) { printf ("father waiting over%d\n", ++i); sleep (1); } return 0; } }
执行./father,当子进程退出后,由于父进程没有对它的退出进行关注,会出现僵尸进程
20786 pts/0 00:00:00 father
20787 pts/0 00:00:00 father 21eba13340b1d3a525d7480ca5bbd370
总结:子进程成为 defunct 直到父进程 wait(),除非父进程忽略了 SIGCLD 。更进一步,父进程没有 wait() 就消亡(仍假设父进程没有忽略 SIGCLD )的子进程(活动的或者 defunct)成为 init 的子进程,init 着手处理它们。
1、父进程通过wait和waitpid等函数等待子进程结束,这会导致父进程挂起。
在上个例子中,如果我们略作修改,在第8行sleep()系统调用前执行wait()或waitpid()系统调用,则子进程在终止后会立即把它在进程表中的数据返回给父进程,此时系统会立即删除该进入点。在这种情形下就不会产生defunct进程。
2. 如果父进程很忙,那么可以用signal函数为SIGCHLD安装handler。在子进程结束后,父进程会收到该信号,可以在handler中调用wait回收。
3. 如果父进程不关心子进程什么时候结束,那么可以用signal(SIGCLD, SIG_IGN)或signal(SIGCHLD, SIG_IGN)通知内核,自己对子进程的结束不感兴趣,那么子进程结束后,内核会回收,并不再给父进程发送信号
4. fork两次,父进程fork一个子进程,然后继续工作,子进程fork一个孙进程后退出,那么孙进程被init接管,孙进程结束后,init会回收。不过子进程的回收还要自己做。 下面就是Stevens给的采用两次folk避免僵尸进程的示例:
#include "apue.h" #include 069d3d88bce9f46cf91e8b21a3bb1b3f int main(void) ...{
pid_t pid;
if ((pid = fork()) 7556d38bf89e4c298ea18b0165fac49b 0)
exit(0); /**//* parent from second fork == first child */
/**//*
* We're the second child; our parent becomes init as soon
* as our real parent calls exit() in the statement above.
* Here's where we'd continue executing, knowing that when
* we're done, init will reap our status.
*/
sleep(2);
printf("second child, parent pid = %d ", getppid());
exit(0);
}
if (waitpid(pid, NULL, 0) != pid) /**//* wait for first child */
err_sys("waitpid error");
/**//*
* We're the parent (the original process); we continue executing,
* knowing that we're not the parent of the second child.
*/
exit(0); }
相关推荐:《Linux视频教程》
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!