我有一些关于僵尸进程的问题
- 僵尸进程概念有什么好处?
- 知道内核为僵尸进程保留(PID,终止状态,资源使用信息)
“资源使用信息”是什么意思 - 僵尸的 PPID() = 1 并且它仍然是僵尸,(init 收获僵尸,因为它默认为 wait())
任何人都可以编写一些 C 代码来制作僵尸,它的父级是 Init? - 僵尸可以拒绝释放一些内存锁吗?
提前致谢
我有一些关于僵尸进程的问题
提前致谢
——僵尸进程概念的好处是什么?
僵尸进程只是一个 pid、一个退出状态和一些会计信息,这些信息会一直存在,直到父进程使用wait
系统调用系列中的一个来获得其最终状态。在父进程调用之前wait
,子进程 ID 必须保持标记为已使用,这样就不能为其他进程分配它。如果要为另一个进程分配一个回收的 pid,则很难区分它与具有相同 pid 的先前进程之间的区别。一次wait
由父进程调用并返回最终退出状态,可以假设没有人会再次在该 pid 处寻找子进程,因此该 pid 现在可以被重用。(我认为在 Linux 上,如果父级将 SIGCHLD 保留为 SIG_IGN,内核将不会保留僵尸,但是将 SIGCHLD 的处置重新注册为 SIG_IGN 不会产生相同的效果)
-- 知道内核为僵尸进程保留(PID,终止状态,资源使用信息)“资源使用信息”是什么意思
其中一些信息是运行程序的内容:
time my_program
会报告。这些值通常在 SIGCHLD 的 siginfo 结构中报告(这不完全是对 的调用wait
),但也可以通过调用 systme 调用的waitid
形式获得(在某些系统上)。查看man sigaction
有关此结构的信息。
-- 僵尸的 PPID() = 1 如何仍然是僵尸,(init 会收割僵尸,因为它默认为 wait())
ppid = 1 的僵尸不应该长时间保持僵尸状态,因为init应该很快就会收获它。一个进程从它死后不久(通过exit
或通过一个杀死它的非传递信号)直到它的父调用wait
并获得它的最终状态,它都将保持僵尸状态。这意味着即使 init 除了一遍又一遍地调用 init 什么都不做,也可能有一小段时间进程可能会显示为僵尸。如果进程长时间(秒)显示为init (0=ppid) 的子进程,则可能有问题。
-- 任何人都可以编写一些 C 代码来制作一个僵尸,它的父级是 Init 吗?
这不清楚,但我认为你想要:
pid_t f = fork();
if (f > 0) {
exit(0); // this is the parent dying, so the child will be an orphan
// and get adopted by init
} else if (f == 0) {
sleep(100); // This is the child doing something that takes enough time for
// its parent to commit suicide (exit(0)) and then for you to
// observe that it has now been adopted by init
exit(0); // And now it dies as well, so init should reap its status, but
// it may be a zombie for a short amount of time first.
} else /* error condition would be handled here */
-- 僵尸可以拒绝释放一些内存锁吗?
僵尸什么都抓不住。他们丢失了所有的内存页面、打开的文件句柄等。操作系统可以弄清楚如何释放的几乎所有东西都应该被释放。不这样做将是一个错误,但请记住,操作系统必须知道它是应该被释放的东西。在用户空间中创建应该在操作系统不知道应该被释放的程序死亡时释放的资源是非常容易的。
僵尸进程纯粹是一个 pid 和退出状态值。无法释放 pid,因为资源(pid)“属于”父级。如果它被释放,另一个进程可能会被分配相同的 pid,然后父进程最终可能会向不相关的进程发送信号;即使父母首先等待确定孩子是否已经退出,也没有办法避免竞争条件。
如果您有兴趣在正在运行的进程列表中查看僵尸进程,请使用以下命令:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(void)
{
pid_t p = fork(); // creates child process and stores the returned PID
if (p != 0) // executed by parent process
{ sleep(1); /* the child process terminates while the parent process sleeps,
the child then becomes a zombie process because the returned status
of the terminated child process isn't checked via a wait() */
system("ps -eo pid,ppid,stat,cmd"); // prints a list of processes in your terminal
}
else // executed by child process
{
exit(0); // the child process terminates immediately
}
return 0;
}
您可以通过列表中的 Z+ 来识别僵尸进程:
注意:如果您使用的是 windows,则必须修改代码。
僵尸进程是已经停止运行但它们的进程表条目仍然存在的进程,因为父进程尚未通过等待系统调用检索它。从技术上讲,每个终止的进程在很短的时间内都是僵尸,但它们可以存活更长时间。
当父进程在子进程完成后不调用等待系统调用时,就会出现更长寿的僵尸进程。发生这种情况的一种情况是父进程编写得不好并且简单地省略了等待调用,或者当父进程在子进程之前死亡并且新的父进程没有对其调用等待。当进程的父进程在子进程之前死亡时,操作系统将子进程分配给“init”进程或 PID 1。即,init 进程“采用”子进程并成为其父进程。这意味着现在当子进程退出时,新的父进程 (init) 必须调用 wait 以获取其退出代码,否则它的进程表条目将永远保留并变成僵尸