Linux环境编程第一天笔记
进程与程序
1. 程序:
是存储在磁盘上的静态指令集合和数据集合,是完成特定任务的代码问价,不占用系统运行资源,只占有磁盘资源。
可执行文件后缀:
windowe --> exe
Android --> apk
Linux --> ELF
在Linux中可执行文件多的类型是ELF(✔)
在Linux中ELF就是可执行文件(×)
ELF文件类型:
-
可执行文件:可被直接运行的文件;
-
可重定位文件:编译器编译过程中生成的中间文件(.o,.a);
-
共享目标文件:可被多个程序共享调用的库文件(Linux下的.so文件)(没有main());
-
核心转储文件:程序崩溃时生成的二进制文件;
readelf 选项 可执行文件名 :查看ELF文件信息
-s:查看ELF文件的符号表,包含符合名称、类型(函数/变量)、所属的节、地址、大小等信息
-h:查看当ELF的头部信息,包含魔数(表示ELF格式)、文件类型、架构、入口地址、程序头/节头偏移量等核心元数据
-l:查看程序头表(Segment 信息,核心是加载地址、权限); -S:查看节区头表(Section 的偏移、大小、权限);
ELF格式文件组成
-
ELF头:位于文件最开始,记录文件的基本信息,比如文件类型,架构,入口地址、程序头表和节区头表的偏移地址和大小。
-
程序头表:描述文件中的段的加载信息,供加载器将文件加载到内存时使用。
-
节区:是ELF文件的实际内容载体,包含代码(.text)数据(.data/.bss)、符号表(.symtab)、重定位节(.reloc)等
-
节区头表:记录每一个节区的名称、类型、大小、在文件中的偏移量等,用于链接过程
-
段:由一个或多个属性相同的节区组成,是加载到内存的基本单元。
2.进程
-
是程序的一次动态执行过程,占用CPU、内存等系统资源、有生命周期。
-
一个程序可以对应多个进程。
-
一个进程在运行过程中,通常只对应一个程序。
3.程序加载为进程的核心步骤
-
用户发起执行请求
-
创建进程控制块
-
内存空间分配
-
加载程序运行依赖
-
设置程序入口与上下文
-
CPU调度执行
-
进程终止,资源回收
当ELF格式的程序被执行时,内核中实际上产生了一个task_struct结构体来表示这个进程这个结构体常常也被称为进程控制块(PCB)
进程控制块(task_struct/PCB)包含
-
进程标识(PID、PPID)
-
进程状态(运行/睡眠/停止/僵尸)
-
资源占用(CPU时间片、内存映射、文件描述符表)
-
调度属性(优先级、调度策略)
-
父子/兄弟进程关系
ps 选项
-ef:排查进程的父子关系
ps -ef | grep nginx //过滤出包含 “nginx” 关键词的进程行。
//直接执行上述命令时,输出会包含grep nginx这个临时进程(干扰排查)
ps -ef | grep nginx | grep -v grep //进一步排除自身
-l :以长格式只查看当前终端的进程。(STAT列为R = 运行、S = 睡眠、Z = 僵尸、T = 停止)
aux:监控进程的资源消耗情况
ps aux | sort -k 3 -r //对输出结果排序,-k 3表示第三列,-r表示降序
axjf:梳理复杂进程的层级关系,排查进程的启动链
-e:显示所有进程
-f:以全格式输出
a:显示所有于终端相关的进程
u:以用户为中心的格式展示信息
x:显示不关联终端的进程(如后台守护进程)
j:显示进程的任务信息
f:以树形结构展示进程间的父子关系
top :动态展示进程的CPU,内存占用率,系统负载,运行时间等信息
htop :等价于top,区别是有颜色,需自行下载
下载命令:sudo apt-get install htop
pstree :以树状结构展示进程层级关系
所有用户进程都有一个共同的祖先进程init(现代linux中systemd已经取代了init)
PID是进程的唯一身份证号,无论是传统Linux还是现代Linux,祖先进程的PID都是1。内核层面有一个0号进程,负责启动PID=1,不参与用户态管理。
在Linux中除过初始化进程,其余所有进程都有一个父进程,如果父进程退出,子进程将会被祖先进程接管。

进程的生命周期
一、进程诞生 父进程调用frok()(部分场景使用exec()加载程序),内核为新的进程分配PID、PIB,内存等资源,新进程进入到就绪态。 就绪队列:当进程已经具备执行条件,但是还未被CPU调度,就会在就绪队列中等待
二、运行阶段
进程运行阶段,主要在就绪态,执行态、睡眠态、挂起态、暂停态、追踪态间转换
-
就绪态→执行态 内核调用sched调度算法,选中就绪队列中的进程,为其分配CPU时间片,进程进入执行态
-
执行态→就绪态 A:进程执行时间超过CPU时间片(时间片耗尽),内核强制收回执行权,进程退回就绪态 B:高优先级进程会抢占低优先级进程的CPU,有更高优先级的进程进入就绪队列,内核触发抢占机制,当前进程退回到就绪态
-
执行态 → 睡眠态(阻塞态) 进程因等待资源或事件完成主动放弃CPU(比如读文件,网络请求),进入睡眠态。
-
可中断睡眠:等待可被打断的事件(如键盘输入),可通过外部信号唤醒,唤醒后回到就绪态
-
不可中断睡眠:比如进程等待磁盘I/O完成(例如向硬盘写入大文件),此时不响应信号避免I/O操作被打断导致数据损坏,I/O操作结束自动回到就绪态。
-
- 睡眠态/就绪态 → 挂起态 挂起态是进程被交换到外存的状态,核心触发条件是系统内存不足:内核为释放内存,将暂时无需调度的进程(就绪态或睡眠态)交换到磁盘,此时进程脱离内存,不参与任何 CPU 调度。当系统内存充足或进程需被唤醒时,内核将其交换回内存,就绪态挂起进程恢复为就绪态,睡眠态挂起进程恢复为睡眠态,继续等待资源/事件。 注意:挂起态与睡眠态的核心区别的是「存储位置」------睡眠态在内存,挂起态在外存。
-
执行态/就绪态 → 暂停态 进程收到特定信号后被动进入「暂停态」,核心触发信号为 SIGSTOP(强制暂停,不可忽略)、SIGTSTP(终端暂停,如 Ctrl+Z)。暂停态进程失去执行能力,不参与 CPU 调度,仅当收到 SIGCONT 继续信号时,恢复为就绪态,重新等待调度。
-
暂停态 → 追踪态 追踪态是调试场景下的特殊状态,当进程被调试器(如 gdb)追踪时,会从暂停态进入追踪态。此时进程受调试器控制,逐行执行指令,调试过程中保持受控暂停,调试结束后,可通过调试器发送信号,让进程恢复为就绪态继续运行。
三、进程终止与消亡(结束阶段)
-
执行态 → 僵尸态 进程通过四种方式终止: ① 正常退出
-
mian函数中return
-
执行exit()/Exit()/_exit()
② 异常退出
-
调用abort()函数
-
接收到终止信号。比如最后一个线程被取消
-
被信号杀死。比如段错误
-
-
僵尸态 → 死亡态 父进程通过调用 wait() 或 waitpid() 函数,读取僵尸态进程的退出状态,完成回收。内核收到回收请求后,彻底释放该进程的 PCB 和 PID 资源,进程进入「死亡态」,至此生命周期完全结束。若父进程未及时回收,僵尸进程会持续占用 PID,耗尽系统 PID 资源后,将无法创建新进程。