僵尸进程
我对僵尸进程有一些疑问,
- 僵尸进程概念有什么好处?
- 知道内核保留僵尸进程的(PID、终止状态、资源使用信息)
“资源使用信息”的含义是什么? - 僵尸的 PPID() = 1 并且它仍然是僵尸,(init 收获僵尸,因为它默认为 wait())
任何人都可以编写一些C代码来创建一个僵尸,它的父级是Init吗? - 僵尸可以拒绝释放内存上的某些锁吗?
提前致谢
I'v some questions about zombie processes
- what the benefits from zombie process concept?
- know that the kernel keeps (PID,termination status, resource usage information) for zombie process
what's the meaning of "resource usage information" - how zombie's PPID() = 1 and it still zombie , (init reaps Zombies because it wait() by default)
can any one write some C code to make a zombie it's parent is Init? - can zombies refusing to release some lock on memory??
thanks in advance
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
-- 僵尸进程概念有什么好处?
僵尸进程只是一个 pid、一个退出状态和一些记帐信息,这些信息会一直保留,直到父进程使用
wait
系列系统调用之一来获取其最终状态。在父进程调用wait
之前,子进程的 ID 必须保持标记为已使用状态,以便其他进程无法分配给它。如果另一个进程被分配了一个回收的 pid,那么就很难区分它和以前具有相同 pid 的进程之间的区别。一旦父进程调用 wait 并返回最终退出状态,就可以假设没有人会再次在该 pid 处查找子进程,因此现在可以重用该 pid。(我认为在 Linux 上,如果父进程将 SIGCHLD 保留为 SIG_IGN,内核将不会保留僵尸,但将 SIGCHLD 的配置重新注册为 SIG_IGN 不会产生相同的效果)
——知道内核保留(PID、终止状态、资源)僵尸进程的“资源使用信息”的含义是什么?
其中一些信息是运行程序时
将报告的内容。这些值通常在 SIGCHLD 的 siginfo 结构中报告(这并不完全是对
wait
的调用),但也可以通过调用 systme 调用的waitid
形式获得(在某些系统上)。有关此结构的信息,请参阅man sigaction
。-- 僵尸的 PPID() = 1 为何仍然是僵尸(init 会收获僵尸,因为它默认为 wait())
ppid = 1 的僵尸不应该长时间保持僵尸状态,因为 init 应该收获很快。进程在死亡后不久就会保持僵尸状态(通过
exit
或通过无人处理的信号杀死它),直到其父进程调用wait
并获得其最终状态。这意味着即使 init 除了一遍又一遍地调用 init 之外什么都不做,也可能在一小段时间内进程可能会显示为僵尸进程。如果进程在很长一段时间(秒)内显示为 init (0=ppid) 的子进程,则可能出现问题。-- 任何人都可以编写一些 C 代码来创建一个僵尸,它的父级是 Init 吗?
这还不清楚,但我认为你想要:
--僵尸可以拒绝释放内存上的某些锁吗?
僵尸无法抓住任何东西。他们丢失了所有内存页面、打开的文件句柄等。几乎所有操作系统可以弄清楚如何释放的东西都应该被释放。不这样做将是一个错误,但请记住操作系统必须知道它是应该被释放的东西。在用户空间中创建资源是很容易的,当程序终止时操作系统不知道应该释放这些资源。
-- what the benefits from zombie process concept?
A zombie process is just a pid, an exit status, and some accounting information that stays around until a parent uses one of the
wait
family of system calls to get its final status. Until a parent callswait
the child's process ID must stay marked as used so that no other process can be assigned it. If another process were to get assigned a recycled pid it would be difficult to tell the difference between it and previous processes that had that same pid. Oncewait
is called by the parent and returns a final exit status it can be assumed that no one will go looking for the child at that pid again, so the pid may now be reused.(I think on Linux if a parent leaves SIGCHLD as SIG_IGN the kernel will not keep zombies around, but that re-registering SIGCHLD's disposition as SIG_IGN does not have the same effect)
-- know that the kernel keeps (PID,termination status, resource usage information) for zombie process what's the meaning of "resource usage information"
Some of this information is what running a program as:
will report. These values are usually reported in the siginfo structure for SIGCHLD (which isn't exactly a call to
wait
) but also available from a call to thewaitid
form of systme call (on some systems). Look atman sigaction
for info about this structure.-- how zombie's PPID() = 1 and it still zombie , (init reaps Zombies because it wait() by default)
A zombie whose ppid = 1 should not stay a zombie for very long because init should reap it pretty quickly. A process will remain a zombie from a point soon after it dies (either via
exit
or by an unhanded signal that kills it) until its parent callswait
and gets it's final status. This means that even if init does nothing but call init over and over there could be a small amount of time where a process may show up as a zombie. If processes show up as children of init (0=ppid) for long amounts of time (seconds) then something is probably wrong.-- can any one write some C code to make a zombie it's parent is Init?
This isn't clear, but I think you want:
-- can zombies refusing to release some lock on memory??
Zombies can't hold onto much of anything. They lose all of their memory pages, open file handles, ...etc. Pretty much everything the operating system can figure out how to free up should get freed. It would be a bug not to, but remember that the OS has to know that it is something that is supposed to be freed. It is very easy to create resources in user space that should be freed when a program dies that the OS doesn't know are supposed to be freed.
僵尸进程纯粹是一个 pid 和退出状态值。无法释放 pid,因为资源(pid)“属于”父级。如果它被释放,另一个进程可能会被分配相同的 pid,然后父进程最终可能会向不相关的进程发送信号;即使父进程首先等待确定子进程是否已退出,也无法避免竞争条件。
A zombie process is purely a pid and exit status value. The pid cannot be released because the resource (the pid) "belongs to" the parent. If it were released, another process might get assigned the same pid, and then the parent could end up sending signals to an unrelated process; even if the parent first waited to determine if the child had exited, there would be no way to avoid race conditions.
如果您有兴趣在正在运行的进程列表中查看僵尸进程,请使用以下命令:
您可以通过列表中的 Z+ 来识别僵尸进程:
注意:如果出现以下情况,您将必须修改代码你正在使用Windows。
If you are interested in seeing the zombie process within a list of running processes use this:
You can identify the zombie process by the Z+ in the list:
NOTE: you will have to modify the code if you are using windows.
僵尸进程是已停止运行但其进程表条目仍然存在的进程,因为父进程尚未通过 wait 系统调用检索它。从技术上讲,每个终止的进程都会在很短的时间内成为僵尸进程,但它们可以存活更长时间。
当父进程在子进程完成后不调用等待系统调用时,就会出现寿命较长的僵尸进程。发生这种情况的一种情况是,父进程编写得不好,只是省略了 wait 调用,或者父进程在子进程之前终止,并且新的父进程没有对其调用 wait 。当一个进程的父进程在子进程之前死亡时,操作系统将子进程分配给“init”进程或PID 1。即init进程“采用”子进程并成为其父进程。这意味着现在当子进程退出时,新的父进程(init)必须调用 wait 来获取其退出代码,否则其进程表条目将永远保留并成为僵尸进程
Zombie processes are processes that have stopped running but their process table entry still exists because the parent process hasn't retrieved it via the wait syscall. Technically each process that terminates is a zombie for a very short period of time but they could live for longer.
Longer lived zombie processes occur when parent processes don't call the wait syscall after the child process has finished. One situation where this occurs is when the parent process is poorly written and simply omits the wait call or when the parent process dies before the child and the new parent process does not call wait on it. When a process' parent dies before the child, the OS assigns the child process to the "init" process or PID 1. i.e. The init process "adopts" the child process and becomes its parent. This means that now when the child process exits the new parent (init) must call waitto get its exit code or its process table entry remains forever and it becomes a zombie
僵尸进程不是生命体,因此无法被杀死。它们的目的有三个主要原因:
wait()
系统调用时维护分配的 pid 号,防止其他fork() 来分配它并避免 pid 冲突。此分配还避免(间接)创建具有该 ID 号的进程组和会话。 PID 分配需要遍历进程表来检查候选 pid 是否已在使用中,因此为死进程维护进程表条目是一个好主意。
exit()
值或状态信息(如果被终止)存储到进行wait()
系统调用的父进程。解决方案非常巧妙,自从它在 AT&T unix 中首次实现以来,没有人认为应该对其进行更改。顺便说一句,除了进程表条目之外,没有为它们分配任何系统资源,因为所有这些信息都存储在那里,因此这些进程不会影响内存或文件描述符。他们也被排除在日程表之外,因此他们无法再次站起来行走。
init()
可能还没有花时间来进行wait()
系统调用,并且它仍在处理最后一个wait()
> 它占了。另一个原因是您指定了另一个catchall进程(Linux允许这样做)而不是init
。仅当僵尸进程进行exit()
系统调用或被信号杀死时,它才会重新定位到正在等待它的进程。在负载较重的系统中,您可以看到 PPID 为 1 的僵尸进程,但并不常见。僵尸只是进程表条目。属于僵尸的所有资源都已归还给系统(该进程只有在释放完所有资源后才进入僵尸状态),因此僵尸进程无法持有任何资源锁(原因很简单,它已经死了) ,因此无法释放它)
想象一个复杂的场景,其中一个进程获取了一个 tcpip 套接字,并且该套接字处于连接状态。然后该进程被成为僵尸的信号杀死,而套接字仍然活着(并且释放该套接字需要仍然运行协议交换来关闭连接)在这种情况下,进程资源实际上被释放(这意味着文件描述符关联到套接字),但套接字关闭被传递给 TCP 内核线程,该线程将继续由内核在释放僵尸资源时进行的隐式
close()
调用启动的工作。如果没有专门用于此目的的内核线程,则该进程仍将处于释放资源的过程中,并且显示为活动状态,直到释放完成。一旦所有资源从垂死的进程中解开/释放,它将被标记为僵尸(尸体会是一个更好的术语)释放资源的任务是在系统时间完成的,因此进程无法控制对它来说,既不附加信号处理程序也不做任何事情......一旦进程死亡,它就会死亡。
Zombie processes are not a living thing, so they cannot be killed. Their purpose is for three main reasons:
wait()
system call, to prevent otherfork()
to allocate it and avoid pid clashes. This allocation also avoids (indirectly) to create process groups and sessions with that id number. PID allocation requires a walk through the process table to check that the candidate pid is not already in use, so maintaining process table entries for walking dead processes is a good idea.exit()
value, or the status info (if killed) to the parent process that makes await()
system call.The solution is so ingenious that nobody has thought it should be changed since its first implementation in AT&T unix. By the way, no system resources other than the process table entry are allocated to them, as all this information is stored there, so no memory or file descriptor implications are due to these processes. They are also excluded from the scheduling tables, so they cannot stand up and walk again.
there's a chance that
init()
has not yet took time to make thewait()
system call, and it's still processing the lastwait()
it accounted for. Another reason is that you have specified another catchall process (linux allows this) instead ofinit
. A Zombie process gets reparented to the process that is waiting for it, only when it makes anexit()
system call or is killed by a signal. In a heavy loaded system you can see zombie processes whose PPID is 1, but is not common.zombies are just process table entries. All resources belonging to a zombie have already been returned to the system (the process only enters the zombie state once it has finished releasing all its resources) so no resource lock can be held by a zombie process (the reason is easy, it is dead, so it cannot release it)
Imagine a complex scenario in which a process has acquired a tcpip socket and the socket is in a connected state. Then that process gets killed by a signal becoming a zombie, while the socket is still alive (and releasing that socket requires still running the protocol exchange to close the connection) In this case, the process resources are actually released (this means the file descriptors associated to the socket) but the socket closing is passed to the TCP kernel thread that will continue the work started by the implicit
close()
call that was made by the kernel when releasing the zombie's resources. If there's no kernel thread dedicated to this purpose, then the process will still be in the process of releasing the resources ---and appears as alive--- until the releasing is done.Once all resources are untied/released from the dying process, it will be marked as a zombie (a corpse would have been a better term) The task of releasing the resources is done in system time, so there's no control that the process can do to it, neither attaching a signal handler or whatever.... once the process is to die, it will die.