---
title: "Linux 进程的生与死"
description: "在 Linux 系统中，进程的生命周期是一个复杂而有趣的过程。本文将详细解析 Linux 进程的创建、运行、死亡以及相关机制。"
date: 2024-07-13T02:53:49Z
canonical: https://xiaobox.github.io/p/2024-07-13-linux-jin-cheng-de-sheng-yu-si/
author: 小盒子
categories: ["系统底层"]
tags: ["Linux"]
source: https://mp.weixin.qq.com/s/GN-ON-7XxCazdOWWhWDLOQ
license: CC BY-NC-SA 4.0
license_url: https://creativecommons.org/licenses/by-nc-sa/4.0/
---

# Linux 进程的生与死

在 Linux 系统中，进程的生命周期是一个复杂而有趣的过程。本文将详细解析 Linux 进程的创建、运行、死亡以及相关机制。

## 进程的诞生

每当一个新进程被创建时，实际上是通过 `fork` 或 `clone` 系统调用将现有进程分裂成两个独立的进程。通常，新创建的进程会立即调用 `execve` 系统调用来替换当前正在执行的二进制文件。例如，当你在 Bash 中运行 `ls` 命令时，Bash 首先会使用 `fork` 创建一个子进程，然后子进程通过 `execve` 调用将自身转变为 `ls` 命令。`ls` 执行完毕后，子进程会结束，返回到原来的 Bash 进程。

在实际应用中，程序几乎不会直接调用这些系统调用，而是使用 libc 封装函数或类似 `system` 这样的 libc 函数。这些函数在底层使用 `fork` 和 `execve` 或它们的变体。

![Image](https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2024-07-13-linux-jin-cheng-de-sheng-yu-si/001-6642d710.jpg)

## 进程的死亡

进程通常通过调用 `exit` 或 `exit_group` 系统调用来结束自身。如果程序员没有显式调用 `exit` 而是从 `main` 返回，编译器会自动调用 `exit`。如果程序没有使用 libc 编译且没有显式调用 `exit`，从 `main` 返回会导致段错误或其他关键信号，因为返回操作会试图从堆栈中弹出非法的返回地址。

此外，进程也可能通过信号（如 `SIGTERM` 或 `SIGKILL`）来终止。最后一种终止进程的方式是直接关闭计算机。

## 进程的身份与僵尸进程

每个进程都有一个唯一的 PID（进程标识符），直到内核在进程结束后回收该 PID。在一个进程的 PID 被回收之前，父进程需要调用 `wait`、`waitpid` 或 `waitid` 来等待子进程结束。如果父进程不等待子进程，子进程将成为僵尸进程，继续占用内核的进程表资源。如果父进程本身结束，子进程将重新分配给 PID 为 1 的进程（通常是 `init` 进程），`init` 会自动调用 `wait` 以释放子进程资源。

## 线程：次要进程

![Image](https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2024-07-13-linux-jin-cheng-de-sheng-yu-si/002-53ec137f.jpg)

在 Linux 中，线程实际上是共享相同内存和一些其他资源的独立进程。线程通过调用带有适当标志的 `clone` 系统调用创建。在内核术语中，每个线程都有自己独特的 PID，但同一进程中的所有线程共享相同的 TGID（线程组 ID），这等同于第一个线程的 PID。因此，从内核的角度来看，PID 实际上标识线程，TGID 标识进程，对于单线程进程，PID 等于 TGID。

## 进程管理

管理 Linux 进程涉及多种技术和工具。系统管理员需要了解如何创建、监视和终止进程，以确保系统的稳定性和效率。

1.  **创建进程**：使用 `fork` 或 `clone` 创建新进程，通常结合 `execve` 执行新程序。
2.  **监视进程**：使用 `ps`、`top`、`htop` 等工具监视系统中的活动进程。`ps` 命令可以显示当前进程的快照，而 `top` 和 `htop` 提供动态实时视图。
3.  **终止进程**：使用 `kill` 命令发送信号终止进程。`kill` 可以发送各种信号，但最常用的是 `SIGTERM`（请求进程终止）和 `SIGKILL`（强制进程终止）。

## 进程间通信

Linux 提供了多种进程间通信（IPC）机制，包括信号、管道、消息队列、共享内存和信号量。每种机制都有其特定的用途和适用场景。

-   **信号**：用于通知进程某些事件的发生。
-   **管道**：用于在父子进程之间传输数据。
-   **消息队列**：允许进程以消息的形式交换数据。
-   **共享内存**：提供最快的 IPC 方法，因为进程可以直接访问共同的内存区域。
-   **信号量**：用于进程间同步，防止资源竞争。

## 进程优先级与调度

Linux 使用调度程序来决定进程的执行顺序和时间。进程的优先级可以通过 `nice` 和 `renice` 命令进行调整。优先级值越低，进程的优先级越高。

-   **实时优先级**：用于实时任务，确保关键任务在规定时间内执行。
-   **普通优先级**：用于一般任务，系统根据优先级和调度策略分配 CPU 时间。

## 进程状态

![Image](https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2024-07-13-linux-jin-cheng-de-sheng-yu-si/003-c1dd2b02.jpg)

一个进程在其生命周期中会经历多个状态，包括：

-   **运行中**：进程正在使用 CPU 。
-   **睡眠中**：进程正在等待某个事件（如 I/O 操作完成）。
-   **停止**：进程被暂停，通常是因为收到了 `SIGSTOP` 信号。
-   **僵尸**：进程已经终止，但其退出状态信息尚未被父进程读取。

了解进程的生命周期和管理技术对于有效使用 Linux 系统至关重要。通过掌握这些知识，系统管理员和开发者可以优化系统性能，确保应用程序的稳定运行。

