Difficulty: Intermediate
What are zombie and orphan processes? How do they arise and how do you prevent or clean them up?
These two terms sound dramatic, and interviewers know candidates often mix them up, so let's separate them cleanly with a simple story. A zombie is a child who has finished its job but whose parent has not yet acknowledged it. An orphan is a child who is still working, but whose parent has died. Both are about the relationship between parent and child, and both are managed through the wait mechanism of Unix.
Start with zombies. When a child process terminates, the kernel frees almost everything: its memory, open files and so on. But it deliberately keeps a tiny entry in the process table containing the child's PID, exit status and resource usage statistics. It does this so that the parent can later retrieve the exit code by calling wait() or waitpid(). Until the parent does so, the child is in the Terminated state but still has a process table entry, and it appears in ps with status Z (defunct). That is a zombie. It uses no CPU and almost no memory, but it holds a PID. If a badly written parent, such as a server that forks a child per request and never waits, accumulates thousands of zombies, the system can run out of PIDs and be unable to create new processes.
You cannot kill a zombie with kill -9, because it is already dead; there is nothing left to kill. The fix is to make its parent reap it. Options include calling wait or waitpid in the parent, installing a SIGCHLD handler that calls waitpid in a loop with WNOHANG, or setting the SIGCHLD disposition to SIG_IGN so the kernel reaps automatically. If the parent itself is buggy and cannot be fixed, killing the parent turns the zombies into orphans, and then init adopts and reaps them.
Now orphans. If a parent exits while its child is still running, the child becomes an orphan. Unix does not leave it hanging: the kernel re-parents it to init (PID 1), or systemd or a designated subreaper on modern Linux. Init continuously calls wait, so when the orphan finishes, it is reaped properly and no zombie remains. Orphans are therefore not a problem in themselves and are actually how daemons are made: a program forks, the parent exits, and the child continues in the background, adopted by init, detached from the terminal.
In container environments there is a practical twist. If the main process in a Docker container is your application rather than a proper init, it becomes PID 1 and may not reap adopted orphans, leading to zombie buildup. That is why tools like tini or the Docker --init flag exist.
To summarize for the interview: a zombie is finished but unreaped and shows Z in ps, an orphan is alive with a dead parent and is adopted by init. Zombies waste process table slots; orphans are harmless. Also mention that wait can return immediately if a child has already exited, which is how reaping works without blocking.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void) {
pid_t pid = fork();
if (pid == 0) {
printf("child %d exiting\n", getpid());
exit(0); /* child terminates immediately */
}
printf("parent sleeping, child is zombie\n");
sleep(30); /* parent never calls wait() */
return 0;
}
During the sleep the child shows state Z because the parent has not called wait(). After the parent exits, init reaps it.
zombie process, orphan process, wait, init, SIGCHLD