In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-04-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/01 Report--
This article will explain in detail how to deal with zombies in Linux. The editor thinks it is very practical, so I share it with you as a reference. I hope you can get something after reading this article.
In popular terms, Zombie process refers to those processes that have been terminated, but still retain some information, waiting for their parent process to collect the corpse for them. That is to say, the parent process is not finished, but the child process is over, the parent process is not dead, and there is no way to collect the body of the child process. It is true that only the dead parent process can collect the body.
First, what is the deadlock process?
In general, the program calls exit (including exit and Exit, the difference between them is not explained here), most of its memory and related resources have been released by the kernel, but this process item (entry) is still retained in the process table (process ID, exit status, occupied resources, etc.), you may ask, why bother to just release the resources? This is because sometimes its parent process wants to know its exit status. A child process is a zombie process, or a zombie process, before it exits but has not been "zombie" by its parent. If the parent process dies before the child process, then the child process will be adopted by the init process, in which case init is the parent process of the child process.
So once the parent process runs for a long time, but there is no call to wait or waitpid, and the SIGCHLD signal is not processed, there is no way for the init process to collect the corpse for the child process. At this time, the child process really becomes a "zombie".
Second, what is the difference between the zombie process and the orphan process?
The answer to this question is very simple, that is, the question of who dies first between father (father process) and son (child process)!
If the father dies while the son is alive, then the son becomes an orphan and the son will be adopted by init. In other words, the init process acts as the father of the son, so when the son dies, the init process will collect the body for him.
If the son dies while the father is still alive, if the father does not collect the body of the son, then the son will become a zombie process.
Third, the harm of the process of death?
The PID of the dead process is still occupied, which means that a large number of child processes will occupy the full process table items, making it impossible for later processes to fork.
The kernel stack of a dead process cannot be released (1K or 2K size), so why keep its kernel stack? because at the bottom of the stack, there is a thread_info structure, which contains the struct_task structure, which contains some exit information.
IV. Ways to avoid the process of deadlock
After searching the Internet, it is concluded that there are three ways:
The signal (SIGCHLD, SIG_IGN) shown in the ① program is called to ignore the SIGCHLD signal, so that after the process ends, the kernel will wai and release resources.
② fork twice, the child process of the first fork exits directly after the completion of the fork, so the child process obtained by the second fork has no father, it will be automatically adopted by the ancestor init, and init will be responsible for releasing its resources, so that there will be no "zombies".
③ wait the child process and release their resources, but the parent process generally has no time to watch and wait for the child process to exit, so it is generally handled by the way of signal. When the SIGCHLD signal is received, the wait operation is called in the signal processing function to release their resources.
Fifth, the analysis and summary of each method to avoid deadlock.
First of all, let's take a look at a program that generates a zombie process, zombie.c:
# include # include # include int main (int argc, const char * argv []) {int I; pid_t pid; for (I = 0; I if ((pid = fork ()) = = 0) / * child * / _ exit (0);} sleep (10); exit (EXIT_SUCCESS);}
Run the program and use ps to view the processes during 10 seconds of sleep, and you will find 10 zombie processes marked "defunct":
Linux zombie process disposal Linux zombie process disposal
Next, let's look at the first method. The program avoid_zombie1.c is as follows:
# include # include int main (int argc, const char * argv []) {pid_t pid; if (SIG_ERR = = signal (SIGCHLD, SIG_IGN)) {perror ("signal error"); _ exit (EXIT_FAILURE) } while (1) {if ((pid = fork ()) = = 0) / * child * / _ exit (0);} exit (EXIT_SUCCESS);}
It is true that no zombie process was found through the ps command while the program was running.
There is this passage in the man document:
Note that even though the default disposition of SIGCHLD is "ignore", explicitly setting the disposition to SIG_IGN results in different treatment of zombie process children.
It means that although the default processing of the signal SIGCHLD is "ignore", the displayed processing method set to SIG_IGN will show different processing methods here (that is, after the child process ends, the resources are automatically reclaimed by the system, so there is no zombie process). This is the difference between signal SIGCHLD and other signals.
There is also a passage in the man document:
The original POSIX standard left the behavior of setting SIGCHLD to SIG_IGN unspecified. It seems that this method is not used on every platform, especially in some old systems, compatibility is not very good, so if you are writing a portable program, this method is not recommended.
The second method is to avoid zombie processes through two fork. Let's look at an example, avoid_zombie2.c:
# include # include int main (int argc, const char * argv []) {pid_t pid; while (1) {if ((pid = fork ()) = = 0) {/ * child * / if ((pid = fork ()) > 0) _ exit (0); sleep (1) Printf ("grandchild, parent id =% ld\ n", (long) getppid ()); _ exit (0);} if (waitpid (- 1, NULL, 0)! = pid) {perror ("waitpid error"); _ exit (EXIT_FAILURE) } exit (EXIT_SUCCESS);}
This is indeed an effective method, but I think this method is not suitable for network concurrent servers, because the efficiency of fork is not high.
Finally, let's take a look at the third and most general method.
Let's take a look at our test program avoid_zombie3.c first.
# include # include void avoid_zombies_handler (int signo) {pid_t pid; int exit_status; int saved_errno = errno; while ((pid = waitpid (- 1, & exit_status, WNOHANG)) > 0) {/ * do nothing * /} errno = saved_errno } int main (int argc, char * argv []) {pid_t pid; int status; struct sigaction child_act; memset (& child_act, 0, sizeof (struct sigaction)); child_act.sa_handler = avoid_zombies_handler; child_act.sa_flags = SA_RESTART | SA_NOCLDSTOP; sigemptyset (& child_act.sa_mask) If (sigaction (SIGCHLD, & child_act, NULL) =-1) {perror ("sigaction error"); _ exit (EXIT_FAILURE);} while (1) {if ((pid = fork ()) = 0) {/ * child process * / _ exit (0) } else if (pid > 0) {/ * parent process * /}} _ exit (EXIT_SUCCESS);}
First of all, you need to know three things:
\ 1. When the signal processing function of a signal is called, the signal is blocked by the operating system (the default sa_flags does not set the SA_NODEFER flag).
two。 When the signal processing function of a signal is called, when the signal is blocked, the signal occurs again and again, then the operating system does not queue them, but only keeps the first and subsequent discarded.
\ 3. Wait series functions have nothing to do with signal SIGCHLD, that is, wait series functions are not driven by signal SIGCHLD.
At this time, someone must be in doubt, since the signal will be discarded, how can we ensure that all zombie processes can be recovered?
With regard to this problem, we can understand it this way, when the child process ends, no matter whether the child process generates the SIGCHLD signal or the child process generates the SIGCHLD signal, and whether the parent process receives the SIGCHLD signal or not, it has nothing to do with the fact that the child process has terminated, that is, the child process termination has nothing to do with the signal, but the operating system will send the signal SIGCHLD to the parent process when the child process terminates. Inform its child process of the termination message, so that the parent process can do the corresponding operation. The purpose of the wait series of functions is to retrieve the information left in the process list when the child process terminates, so any time you call while ((pid = waitpid (- 1, & exit_status, WNOHANG)) > 0), you can retrieve all the zombie process information (see the following program). But the reason why it is dealt with here in the signal processing function is that when the child process ends is an asynchronous event, and the signal mechanism is used to deal with the asynchronous event, so when the child process ends, its residual information can be quickly recovered, so that a large number of zombie processes will not be accumulated in the system.
It can also be understood this way: the system strings all zombie processes together to form a zombie process linked list, and while ((pid = waitpid (- 1, & exit_status, WNOHANG)) > 0) is used to empty the linked list until waitpid () returns 0, indicating that there are no zombie processes, or-1, indicating an error (when the error code errno is ECHILD, it also indicates that there are no zombie processes).
Knowing the above knowledge points, you can understand why while ((pid = waitpid (- 1, & exit_status, WNOHANG)) > 0) can recycle all zombie processes.
We can add the corresponding print information to the above signal processing function:
Static int num1 = 0 static int num2 = 0; void avoid_zombies_handler (int signo) {pid_t pid; int exit_status; int saved_errno = errno; printf ("num1 =% d\ n", + + num1); while ((pid = waitpid (- 1, & exit_status, WNOHANG)) > 0) {printf ("num2 =% d\ n", + + num2);} errno = saved_errno;}
Print the results you will find that when num1 increments by 1, that is, each call to the signal processing function, num2 will generally increase a lot, that is, while loops many times, so although some SIGCHLD signals are discarded, we do not have to worry about the residual information of the child process will not be recovered. When you exit the while loop, it is proved that there are no zombie processes in the system at this time, so after exiting the signal handler, the only blocked SIGCHLD signal will trigger the signal handler again, so we don't have to worry. We do not guard against the worst-case scenario, that is, all the previous signals are discarded, and only the last SIGCHLD signal is captured, thus triggering the signal processing function, so we do not have to worry, because the while loop will retrieve all the zombie process information at once, but this time there are much more times, of course, this is only hypothetical. This is not the case in a general system (you can refer to the last program example in this article).
To prove that the wait system function has nothing to do with the signal SIGCHLD, we can do a simple experiment with the following code:
# include # include int main (int argc, char * argv []) {int I; pid_t pid; for (I = 0; I if ((pid = fork ()) = 0) / * child * / _ exit (0);} sleep (10); while (waitpid (- 1, NULL, WNOHANG) > 0) {/ * do nothing * /} sleep (10) _ exit (EXIT_SUCCESS);}
The following is the print result:
Linux zombie process disposal Linux zombie process disposal
You can see that five zombie processes were accumulated in the system at the first sleep, and all five zombie processes were withdrawn at the second sleep. This also clearly shows the advantage of using signal processing function, that is, it can ensure that the system will not accumulate a large number of zombie processes, and it can quickly clean up the zombie processes in the system.
This is the end of the article on "how to deal with the zombie process in Linux". I hope the above content can be helpful to you, so that you can learn more knowledge. if you think the article is good, please share it for more people to see.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.