终止过程
一旦进程创建了,它是如何结束的呢?进程的终止是进程生命周期中的一个关键部分,它确保了系统资源的有效管理。
进程通常通过调用 _exit 系统调用来终止。此操作向内核发出信号,表明进程已完成,其资源(如内存和文件描述符)可以被回收。退出时,进程会向内核提供一个终止状态,这是一个整数值。按照惯例,状态 0 表示成功执行,而非零值表示发生错误。
然而,调用 _exit 并不会立即清除进程。父进程必须使用 wait 系统调用来确认其子进程的终止。此调用允许父进程检索子进程的终止状态。这种两步机制对于正确的进程清理至关重要。另一种 linux kill child process(终止子进程)的方式是使用信号,这是我们将在后续课程中探讨的主题。
孤儿进程 (Orphan Processes)
如果父进程在其子进程终止之前就终止了,会发生什么?子进程就成了“孤儿”。由于其原始父进程无法再调用 wait,内核会介入。孤儿进程会立即被一个特殊的系统进程(通常是 init,进程 ID 为 1)收养,该进程被认为是所有进程的祖先。然后 init 进程承担起父进程的角色,定期调用 wait 来收集其所有被收养子进程的终止状态,使它们能够干净地终止。
僵尸进程 (Zombie Processes)
当子进程终止,但其父进程尚未调用 wait 时,会发生不同的情况。在这种状态下,子进程就成了“僵尸”进程。内核会释放僵尸进程的大部分资源,但它会在进程表中保留一个条目。该条目包含进程 ID 和终止状态,等待父进程来收集。
僵尸进程已经死亡,因此它们不消耗 CPU 时间。你无法使用信号来终止它们,因为它们没有在运行。父进程调用 wait 来清理僵尸进程的过程称为“回收”(reaping)。如果父进程从不调用 wait,这些僵尸进程就会积累。虽然少量无害,但大量僵尸进程会填满进程表,阻止新进程的创建。在父进程也终止的情况下,init 会收养并回收僵尸进程。
僵尸进程 vs 孤儿进程
理解 zombie vs orphan process(僵尸进程与孤儿进程的对比)之间的区别,是诊断进程相关问题的关键。
- 孤儿进程 是一个活动的、正在运行的进程,其父进程已经死亡。它被
init收养并继续执行,直到它自己完成。 - 僵尸进程 是一个已死的进程,它已经完成了执行,但在进程表中仍有一个条目。它正在等待其父进程读取其退出状态。
简而言之,孤儿是“活着但没有父母”,而僵尸是“死了但尚未被父进程完全回收”。