云计算百科
云计算领域专业知识百科平台

Linux进程核心考点精要

Linux 进程核心考点与实战笔记(嵌入式/后台面试向)

一、进程本质与 PCB 管理

进程是程序的一次动态执行过程,区别于磁盘上静态的二进制文件(如 a.out)。操作系统通过进程控制块(PCB)(Linux 中为 task_struct 结构体)对进程进行全生命周期管理 。

核心要素说明面试关键点
PID 进程唯一标识符 全局唯一,回收后可能复用
资源描述 打开文件描述符表、内存映射、IO 设备 文件描述符继承机制
调度信息 优先级、状态、时间片统计 CFS 调度算法基础
上下文 寄存器值、栈指针、程序计数器 进程切换时的保存与恢复
权限控制 UID/GID、umask 掩码 安全性与文件访问控制

并发 vs 并行:

  • 并发 (Concurrency):单核 CPU 通过时间片轮转快速切换任务,宏观“同时”,微观串行。
  • 并行 (Parallelism):多核 CPU 多个任务在不同核心上真正同时执行 。

二、虚拟内存分布(32 位模型)

32 位系统下,4GB 地址空间通常划分为 3GB 用户空间 + 1GB 内核空间。

高地址
+——————+
| 内核空间 (1G) | <— 用户态不可直接访问
+——————+
| 栈 | <— 向下增长 (默认 8M, ulimit -s)
+——————+
| 共享库/mmap 区 | <— 动态库、文件映射
+——————+
| 堆 | <— 向上增长 (malloc/free)
+——————+
| 数据段 (BSS) | <— 未初始化全局/静态变量
+——————+
| 数据段 (Data) | <— 已初始化全局/静态变量
+——————+
| 代码段 (Text) | <— 只读指令
+——————+
低地址

资源限制查看: 使用 ulimit -a 查看进程资源约束,嵌入式开发需重点关注:

  • open files (-n):默认 1024,高并发服务器需调大。
  • stack size (-s):默认 8192KB,递归过深易导致 Stack Overflow 。

三、fork() 机制与写时复制 (COW)

fork() 是 Linux 创建进程的核心系统调用,其特性为**“一次调用,两次返回”**。

1. 返回值逻辑

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
pid_t pid = fork();

if (pid < 0) {
// 创建失败
perror("fork failed");
exit(1);
} else if (pid == 0) {
// 子进程逻辑
printf("Child Process: PID=%d, PPID=%d
", getpid(), getppid());
exit(0);
} else {
// 父进程逻辑 printf("Parent Process: PID=%d, Child_PID=%d
", getpid(), pid);
// 必须回收子进程,防止僵尸
wait(NULL);
}
return 0;
}

2. 核心特性解析

  • 代码执行点:子进程从 fork() 返回处开始执行,而非重新运行 main。
  • 独立性:父子进程拥有独立的 PID 和 PCB,但初始代码逻辑相同。
  • 写时复制 (Copy On Write):
    • fork 瞬间:父子进程共享物理内存页,内核将页面标记为只读。
    • 修改发生时:若任意一方尝试写入,内核触发缺页异常,单独拷贝一份物理内存给修改方,实现延迟拷贝,极大降低开销 。
  • 调度不确定性:父子进程谁先运行由内核调度器决定,不可假设顺序。

四、进程状态流转与特殊形态

Linux 进程状态主要包含以下几种,其中 Z 态 是面试高频考点。

状态码状态名称含义能否被信号唤醒
R Running 正在运行或在就绪队列等待调度 N/A
S Interruptible Sleep 可中断睡眠,等待资源 能
D Uninterruptible Sleep 不可中断睡眠,通常在等待 IO 不能
T Stopped 暂停态,收到 SIGSTOP 等信号 能 (SIGCONT)
Z Zombie 僵死态,进程结束但 PCB 未回收 不能

重点辨析:孤儿进程 vs 僵尸进程

  • 孤儿进程 (Orphan):父进程先退出,子进程仍在运行。
    • 处理机制:被 init (PID 1) 或 systemd 进程收养,资源自动回收,无害。
  • 僵尸进程 (Zombie):子进程先退出,父进程未调用 wait/waitpid 回收。
    • 危害:用户空间资源已释放,但 PCB 仍驻留内核,占用内核内存槽位。大量僵尸进程会导致无法创建新进程 。
    • 解决:父进程必须正确处理信号或调用 wait 系列函数;若父进程僵死,需杀死父进程让 init 收养。

五、进程退出的 8 种方式与 exit/_exit 区别

进程终止分为正常退出、系统调用退出和异常终止。

1. 退出方式分类

  • 正常退出:
  • main 函数 return。
  • exit():C 库函数,执行清理工作。
  • pthread_exit():主线程退出。
    • 系统调用退出: 4. _exit() / _Exit():直接陷入内核,不执行用户态清理。
    • 异常终止: 5. abort():发送 SIGABRT 信号。 6. 信号杀死:kill 命令或代码触发 SIGKILL/SIGTERM。 7. 线程取消:最后一个线程被 pthread_cancel。

    2. 核心面试题:exit() vs _exit()

    特性exit()_exit() / _Exit()
    归属 C 标准库 (stdlib.h) 系统调用 (unistd.h)
    缓冲区处理 刷新 stdio 缓冲区 (fwrite 内容写入文件) 不刷新,直接丢弃缓冲区数据
    清理钩子 执行 atexit 注册的回调函数 不执行任何清理钩子
    底层动作 调用 _exit() 进入内核 直接进入内核释放资源
    应用场景 普通程序正常结束 fork 后的子进程出错退出 (避免重复刷新父进程缓冲区)

    代码示例:验证缓冲区差异

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>

    int main() {
    printf("Before fork: This is in buffer
    "); // 此时数据在缓冲区,未写入终端

    pid_t pid = fork();

    if (pid == 0) {
    // 子进程:使用 _exit 避免刷新父进程的缓冲区,防止输出重复
    _exit(0);
    } else {
    // 父进程:等待后正常退出,会刷新缓冲区
    sleep(1); exit(0);
    }
    // 若子进程也用 exit(0),"Before fork…" 会被打印两次
    }

    六、常用调试命令与调度算法

    1. 关键命令

    • ps aux:静态快照,查看 PID、STAT (状态)、CMD。
    • top:动态监控,实时查看 CPU/Mem 占用,按 P 按 CPU 排序,M 按内存排序。
    • pstree:树状展示进程父子关系,快速定位孤儿/僵尸链。
    • kill -l:查看所有可用信号列表。

    2. Linux 调度策略

    现代 Linux 内核默认采用 CFS (Completely Fair Scheduler,完全公平调度) 算法,取代了早期的 O(1) 调度器。

    • 核心思想:基于红黑树维护所有可运行进程,根据 vruntime (虚拟运行时间) 选择最小节点执行,确保每个进程获得公平的 CPU 时间片 。
    • 其他策略:实时进程可采用 SCHED_FIFO (先进先出) 或 SCHED_RR (时间片轮转)。## 七、总结与进阶方向 进程管理是嵌入式 Linux 与后台开发的基石。面试中需熟练掌握:
  • fork 的 COW 机制及其对性能的影响。
  • 僵尸进程的产生原理及 wait/waitpid 的正确用法。
  • exit 与 _exit 的底层区别(缓冲区与钩子函数)。
  • 进程状态机转换,特别是 D 态与 Z 态的处理。
  • 后续学习路线:

    • 进程回收:深入 waitpid 选项与非阻塞回收。
    • 进程映像替换:exec 族函数 (execl, execvp 等) 的使用场景。
    • 进程间通信 (IPC):管道 (Pipe)、消息队列、共享内存、信号量。

    参考来源

    • 网易后端面试全攻略:从高频考点到实战方案
    • 贝壳找房Java笔试全解析:考点分布、OOM排查与排序算法实战

     

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » Linux进程核心考点精要
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!