1. What is a zombie process?
The zombie, defunct, PS, and top commands of zombie processes can be seen. It refers to a process in the "zombie" state. Such a process is dead, but it is still stored in some way. It is said that it has died because its resources (memory, peripheral links, etc.) have been released and it will never run again. The process descriptor still exists in the system progress table.
Check the Linux-Defined Process status: Include/Linux/sched. h.
/* * Task state bitmask. NOTE! These bits are also * encoded in fs/proc/array.c: get_task_state(). * * We have two separate sets of flags: task->state * is about runnability, while task->exit_state are * about the task exiting. Confusing, but this way * modifying one set can't modify the other one by * mistake. */#define TASK_RUNNING 0#define TASK_INTERRUPTIBLE 1#define TASK_UNINTERRUPTIBLE 2#define __TASK_STOPPED 4#define __TASK_TRACED 8/* in tsk->exit_state */#define EXIT_ZOMBIE 16#define EXIT_DEAD 32/* in tsk->state again */#define TASK_DEAD 64#define TASK_WAKEKILL 128#define TASK_WAKING 256
Let's see the exit_zombie number of 16. That's right, it's a state of the process. It's not surprising that a zombie process is triggered.
Ii. How to generate zombie Processes
So how is a zombie process produced? This should begin with the process creation and destruction methods in Linux. The creation of a process is like the birth of a person. Everyone is the same. However, destruction is different. It is similar to humans who want to handle post-events. The complexity of post-Events after death varies greatly.
The destruction of a process takes two phases:
1. Process Termination (return in main function or exit in program execution) or killed (signal sigterm, sigkill)
2. The parent process of the process must be called when the child process ends or the wait4 (wait, waitpid) system call has been called. The system call causes the kernel to release resources reserved for the child process.
Only when 1 is true and 2 is not true will a zombie process appear. That is to say, after the process is terminated (1), its process descriptor has not been deleted from the Progress table, it is a so-called zombie process. Zombie processes may be stored in the progress table until the system is restarted.
3. How to Avoid zombie Processes
First of all, it should be noted that every process (except init) has to go through freezing. Here we will discuss how to deal with zombie processes as soon as possible.
1. the parent process calls the wait4 () or waipid () system call, and there are other wait () class library functions, such as wait3 () and wait () however, in Linux, these library functions are implemented by calling the wait4 () and watipid () systems.
Because the parent process calls wait (), the classic practice is that the parent process registers the sigchld signal and wait () in the signal processing function ()
Void ouch (INT sig) {Wait (); // In the signal processing function, wait ()} Main () {signal (sigchld, ouch); // Do What You wat}
2. Two forks, using orphan Process)
The specific method is to first use the parent process fork () as a sub-process, and the parent process blocks the wait. Then let the sub-process immediately fork () A grandson process, and let the sub-process immediately quit. Use the Sun Tzu process to process transactions. At this time, because the sub-process has exited, the Sun Tzu process becomes an orphan process and is adopted by init. After the child process exits immediately, the parent process receives the signal and destroys the child process correctly.
For more information, see apue.
3. The parent process ignores the sigchld signal (this usage is limited, and it seems to be limited to Linux 2.6 and higher kernel)
Signal (sigchld, sig_ign); // ignore the sigchld signal pid = fork (); // The sub-process here will not be zombie
Man sigaction has the following description:
POSIX.1-1990 disallowed setting the action for SIGCHLD to SIG_IGN. POSIX.1-2001 allows this possibility,so that ignoring SIGCHLD can be used to prevent the creation of zombies (see wait(2)). Nevertheless, thehistorical BSD and System V behaviors for ignoring SIGCHLD differ, so that the only completely portablemethod of ensuring that terminated children do not become zombies is to catch the SIGCHLD signal andperform a wait(2) or similar.
MAN 2 wait
POSIX.1-2001 specifies that if the disposition of SIGCHLD is set to SIG_IGN or the SA_NOCLDWAIT flag isset for SIGCHLD (see sigaction(2)), then children that terminate do not become zombies and a call towait() or waitpid() will block until all children have terminated, and then fail with errno set to ECHILD.(The original POSIX standard left the behavior of setting SIGCHLD to SIG_IGN unspecified. Note that eventhough the default disposition of SIGCHLD is "ignore", explicitly setting the disposition to SIG_IGNresults in different treatment of zombie process children.) Linux 2.6 conforms to this specification.However, Linux 2.4 (and earlier) does not: if a wait() or waitpid() call is made while SIGCHLD is beingignored, the call behaves just as though SIGCHLD were not being ignored, that is, the call blocks untilthe next child terminates and then returns the process ID and status of that child.
What if the parent process ignores the sigchld signal and then calls wait4 () or waitpid?
The do_policy_parent (struct task_struct * Tsk, int sig) function in kernle/signal. C has the following description:
/** We are exiting and our parent doesn't care. POSIX.1 defines special semantics for setting SIGCHLD to SIG_IGN* or setting the SA_NOCLDWAIT flag: we should be reaped automatically and not left for our parent's wait4 call.* Rather than having the parent do it as a magic kind of signal handler, we just set this to tell do_exit that* we can be cleaned up without becoming a zombie. Note that we still call __wake_up_parent in this case,* because a blocked sys_wait4 might now return -ECHILD.** Whether we send SIGCHLD or not for SA_NOCLDWAIT is implementation-defined: we do (if you don't want* it, just use SIG_IGN instead).*/
So, why does the parent process signal (sigchld, sig_ign); then the child process will not be botnets? Is it because the child process inherits the parent process to ignore the sigchld attribute.
I thought that executing the exit () function when the sub-process exits will check whether sigchld is ignored. If ignored, the kernel will clear all the resources of the sub-process in the do_exit () function.
I did a small experiment to prove that I was wrong.
Int main () {int I = 0; pid_t pid = 0; signal (sigchld, sig_ign); // The parent process ignore sigchld pid = fork (); If (pid> 0) {puts ("I am parent"); for (I = 0; I <60; I ++) {printf ("parent: % d \ n", I ); sleep (1) ;}} else if (pid = 0) {signal (sigchld, sig_dfl); // The sub-process restores the default sigchld behavior puts ("I am child "); exit (0);} return 0 ;}
After the program is executed, no zombie process occurs. It can be seen that the setting of the parent process signal (sigchld, sig_ign) does not affect the sub-process's out-of-row, at least it does not affect the sub-process exit.
So why?