找回密码
立即注册
搜索
发回帖 发新帖

6450

积分

0

好友

801

主题
发表于 前天 11:20 | 查看: 7| 回复: 0

前言

在 Linux 中执行一次 ls、启动一个应用程序、运行一个 ROS2 节点,背后都离不开进程。但一个进程,远不只是“正在运行的程序”。

本文阅读路线

进程是什么 → task_struct → 状态与 PID → 进程树 → 内存 → 文件系统 → 文件描述符 → Namespace → 调度与排查

01 · 什么是 Linux 进程?

程序是存储在磁盘上的静态可执行文件;进程是程序运行时在操作系统中的执行实例。

./hello & ./hello & ./hello &

这三次运行的是同一个程序,但会创建三个独立的进程。它们拥有不同的进程 ID,通常具有各自独立的虚拟地址空间,并分别参与内核调度。

02 · 一张图看懂进程结构

Linux进程核心数据结构task_struct架构图

图:Linux 进程核心数据结构关系(示意图,具体字段随内核版本变化)

Linux 内核使用 task_struct 描述一个任务(task)。一个任务可以是普通进程中的主线程,也可以是同一线程组中的其他线程。

Linux task_struct结构体示意代码

记住一句话:task_struct 是任务信息的核心入口,通过指针关联地址空间、文件、目录、命名空间等资源。

03 · 状态与身份:state / pid / tgid

任务状态

任务不一定时刻占用 CPU,它可能运行、等待事件、停止或退出。常见的 ps 状态包括:

标识 含义
R 运行或可运行
S 可中断睡眠
D 不可中断睡眠
T 停止
Z 僵尸状态

内核任务运行状态与退出状态分别涉及不同字段;这里是用户空间观察到的简化分类。

pid 与 tgid

pid 标识一个内核任务;tgid 标识其所属线程组。 同一进程的多个线程通常具有不同的 pid,但共享 tgid。

线程 pid tgid
主线程 1000 1000
工作线程 A 1001 1000
工作线程 B 1002 1000
ps -eo pid,ppid,stat,comm
ls /proc/1000/task

04 · 进程关系:父进程与子进程

进程之间往往具有父子关系。real_parent 指向真实父任务;children 是子任务链表的表头;sibling 将子任务连接到父任务的子链表;group_leader 指向线程组组长。

pstree -p

通常可以通过 fork() 创建子进程,再通过 execve() 在子进程中加载新的程序映像。

05 · 内存管理:mm_struct

mm 指向 mm_struct,描述用户虚拟地址空间。它涉及代码段、数据段、BSS、堆、栈、内存映射区域以及页表等信息。

成员或区域 作用
start_code / end_code 代码区域边界
start_data / end_data 数据区域边界
start_brk / brk 堆的初始与当前 program break
start_stack 初始用户栈位置
VMA 描述各段虚拟内存映射

程序使用的是虚拟地址,CPU 借助 MMU 和页表转换为物理地址。不同进程的相同虚拟地址,不一定映射到同一物理页面。

内核版本提示:图中的 mm_struct.mmap 体现的是较早版本的 VMA 链表管理方式;现代内核已使用 Maple Tree 管理虚拟内存区域。

内核线程一般没有独立的用户地址空间,因此其 mm 通常为 NULL。

cat /proc/1234/maps
cat /proc/1234/smaps_rollup

06 · 文件系统:fs_struct

fs 指向 fs_struct,保存任务的文件系统上下文。其中 root 表示进程视角中的根目录,pwd 表示当前工作目录。

它们并非普通路径字符串,而是由 struct path 关联挂载点与目录项。目录项 dentry 又可关联描述文件对象元数据的 inode。

readlink /proc/1234/cwd
readlink /proc/1234/root

07 · 打开的文件:files_struct

files 指向 files_struct,其中的文件描述符表将整数 fd 映射到内核的 struct file 对象。

文件描述符 常见用途
0 标准输入 stdin
1 标准输出 stdout
2 标准错误 stderr
3、4、... 文件、管道、Socket 等

一个文件描述符只是表中的索引,不是文件本身。多个描述符还可能指向同一个 struct file,例如 dup() 后会共享打开文件对象及其文件偏移量。

ls -l /proc/1234/fd

08 · 命名空间:nsproxy

nsproxy 关联任务的部分命名空间,帮助实现进程视图隔离。常见类型有 PID、Mount、Network、UTS、IPC、Cgroup 和 Time Namespace。

例如,容器内部看到的 PID 1,在宿主机中可能是另一个 PID;不同网络命名空间可以拥有各自的网络接口和路由配置。

User Namespace 等信息并非全部直接保存在 nsproxy 中。容器隔离通常还结合 Cgroup 和其他内核机制。

ls -l /proc/1234/ns

09 · CPU 调度:prio

prio 等字段记录任务的调度优先级属性。内核还会结合调度策略、调度类与调度实体等信息决定任务如何获得 CPU。

常见调度策略包括 SCHED_OTHER、SCHED_FIFO、SCHED_RR 和 SCHED_DEADLINE。

ps -eo pid,comm,pri,ni,cls

10 · 一张排查命令速查表

想看什么 命令
进程状态 cat /proc/PID/status
虚拟内存映射 cat /proc/PID/maps
线程列表 ls /proc/PID/task
打开的文件 ls -l /proc/PID/fd
工作目录 readlink /proc/PID/cwd
命名空间 ls -l /proc/PID/ns
进程树 pstree -p

写在最后

Linux 进程并不只是一个正在运行的程序,而是内核围绕任务执行、资源管理和系统隔离组织起来的一整套运行环境。

最后再记住这张关系图:
task_struct 管任务;mm_struct 管地址空间;fs_struct 管目录上下文;files_struct 管文件描述符;nsproxy 关联部分命名空间。

理解这些关系,有助于排查进程阻塞、内存异常、文件描述符泄漏、线程调度以及容器隔离等实际问题。更多操作系统底层的深入讨论,也可以在云栈社区与大家一起交流。

注:文中代码与结构体字段为讲解示意,实际以目标内核版本源码为准。




上一篇:Linux底层逻辑:进程如何使用虚拟内存?mmap、栈与ptmalloc详解
下一篇:Linux进程创建机制图解:从fork到copy_process的完整路径
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-10-25 03:32 , Processed in 0.077953 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表