什么是僵尸进程?是什么导致了它们的出现?是否存在僵尸对象?

36

我能找到有关僵尸的问题,但没有直接解释它们是什么以及为什么和如何发生的。有一些问题涉及在回答特定问题的上下文中僵尸进程是什么,但没有涉及到其原因。

还有关于僵尸进程的问题以及与Objective-C/Cocoa相关的僵尸对象的问题。它们之间有什么区别或联系吗?在Mac/iPhone上出现"EXEC_BAD_ACCESS"错误(或其他平台上类似的错误)是否意味着存在僵尸?

如何预防僵尸问题,并且有没有最佳实践可以帮助避免它们?

如果可能的话,将这些信息放在一个地方会很有帮助。此问题旨在不针对任何特定平台或编程语言。

2个回答

38

僵尸进程和僵尸对象是完全不相关的。当父进程启动一个子进程,而子进程结束后,父进程没有接收到子进程的退出码时,就会出现僵尸进程。这时,进程对象必须保持存在状态,直到处理完子进程的退出码为止——该进程对象不占用系统资源,已经“死亡”,但仍然存在,因此被称为“僵尸”。

“僵尸对象”是Cocoa/CoreFoundation中用于帮助您捕获内存错误的调试功能——通常情况下,当对象的引用计数归零时,它会立即被释放,但这会使调试变得困难。相反,如果启用了“僵尸对象”,则对象的内存不会立即被释放,而只是标记为“僵尸”,任何后续尝试使用这些对象的操作都将被记录,您可以跟踪在代码中使用对象超出其生命周期的位置。

EXEC_BAD_ACCESS 是一种常见的“您使用了一个不良指针”的异常,就像我执行以下操作:

(*(0x42)) = 5;

好的,我明白什么是僵尸进程了,但为什么会发生这种情况呢?这是父进程编程错误、系统故障还是超自然力量?所谓的僵尸对象用于捕捉悬空指针,即引用已被释放内存的对象的指针。 - yabada
是的,是父级对象出了问题。你对“僵尸对象”有了正确的理解。 - Ana Betts
从概念上讲,我认为它们是相关的:两者都已经被“杀死”,但在某种程度上仍然“活着”。 - yabada
关于“EXEC_BAD_ACCESS”类型的错误,似乎并不一定是僵尸进程。如果您进行了一些可怕的指针算术运算,可能会得到这种类型的错误,但您仍然可以在某个地方获得有效的对象(只需正确引用指针即可)。此外,我理解您的例子的意思,但从理论上讲,如果星星都排列得正确(不太可能,但只是说说而已),它也可能起作用,对吧? - yabada

9
当一个进程结束时,它的大部分状态仍然存在于内核中,因为其父进程可能还想查看一些内容,比如其返回值,这些需要被存储在某个地方。当父进程调用wait()或waitpid()时,它告诉内核把这些都丢掉,因为它已经完成了任务。在父进程采取行动之前,子进程会保留一个pid并使用资源。这些未被回收的子进程称为僵尸进程。即使杀死一个僵尸进程也不能将其移除,它必须被父进程等待回收。如果父进程死亡,它们将被传递给unix系统上的“init”,它的唯一工作就是等待清理它们。
我从来没有听说过“zombie objects”,但我认为它指的是那些没有被垃圾回收器清理或者有循环引用等问题的对象,它们不会被垃圾回收器清理。这个比喻非常相似:fork()==malloc(),wait()==free(),在某种程度上是类似的。(当然并不完美)。

僵尸进程消耗的唯一资源是其在内核进程表中的条目。此时,其他所有内容都已被回收,因为它已经死了。 (而且 init 还有其他职责,但通常只有在出现问题时才会看到这些职责。) - Donal Fellows
@donal:我认为信号代码也在其中。并且它在等待期间/之后仍然可以编写核心吗?此外,通过“使用资源”,我主要是指pid本身,因为您可能会耗尽这些资源,特别是在每个用户的基础上。 :-) - eruciform
嗯,我也认为“僵尸对象”是由于循环引用阻止垃圾收集器收集某些对象的结果。你会说这个线程是否否定了这一点? - samfr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接