从系统的角度分析影响程序执行性能的因素
1 Linux 精简结构
宏观上 Linux 的体系结构分为用户态和内核态,实现了三大核心功能进程管理、内存管理和虚拟文件系统管理,使应用程序能更好地利用计算机的硬件资源。
2 计算机三大法宝
2.1 存储程序
存储程序计算机即冯·诺依曼计算机,它由运算器、控制器、存储器、输入设备和输出设备五部分组成,其中指令和数据以二进制形式顺序存放在存储器中,计算机顺序取出、分析并执行指令。
2.2 堆栈机制
堆栈是记录程序运行时函数调用路径和参数存储的区域,其主要作用有记录函数调用、传递函数参数、保存返回值地址、提供函数内部局部变量的存储空间。
2.3 中断机制
中断本质是 CPU 对外开放的实时受控接口,其类别如下几种:
类别 | 原因 | 异步/同步 | 返回行为 |
---|---|---|---|
中断 | 来自 IO 的信号 | 异步 | 返回下一条指令 |
陷阱 | 主动的异常 | 同步 | 返回下一条指令 |
故障 | 可恢复的错误 | 同步 | 返回当前指令 |
终止 | 不可恢复的错误 | 同步 | 不返回 |
特殊中断:系统调用
系统调用发生在用户态切换到内核态过程中,其意义是为用户进程与硬件设备之间提供了交互接口。
3 进程管理
3.1 进程状态
-
TASK_RUNNING:进程准备执行或正在执行。
-
TASK_INTERRUPTIBLE:进程被阻塞,可提前被信号打断唤醒。
-
TASK_UNINTERRUPTIBLE:进程被阻塞,不可提前被信号打断唤醒。
-
TASK_STOPPED:进程暂停运行。
-
TASK_ZOMBIE:进程被终止但未回收。
3.2 进程创建
init_task 是 0 号进程的进程描述符结构体变量,其初始化通过硬编码方式固定;其他所有进程都是通过 do_fork() 复制父进程的方式初始化。
3.3 进程调度
进程的调度时机发生在以下两种情况,一是内核线程主动调用 schedule() 让出 CPU;二是中断处理程序主动调用 schedule() 让出 CPU。进程的切换从本质上讲由两步组成,一是切换全局目录以安装一个新的地址空间;二是切换内核态堆栈和硬件上下文。
4 内存管理
在进程看来,内存地址空间分为内核态和用户态两部分,并且它们会被划分为不同区域以适用于不同目的。
内核地址空间划分为:直接映射区、动态内存映射区、永久内存映射区、固定映射区。
用户地址空间划分为:
-
STACK:用户进程栈。
-
MMAP:共享库及匿名文件的映射区域。
-
HEAP:运行时的堆,在程序运行中使用 malloc 申请的内存区域。
-
BSS:存放程序中未初始化的全局变量。
-
DATA:数据段,映射程序中已经初始化的全局变量。
-
TEXT:代码段可执行代码、字符串字面值、只读变量。
Linux 的地址映射过程为逻辑地址 –> 线性地址 –> 物理地址,其中分段机制把逻辑地址转换为线性地址,分页机制把线性地址转换为物理地址。
5 虚拟文件系统管理
Linux 系统内核在用户进程与实际文件系统之间加入了一个抽象层,称为虚拟文件系统。主要意义在于支持不同的文件系统,提供管理文件目录的统一方法以及允许访问其他操作系统的文件。
6 举例打开文件
6.1 具体流程
- 使用 open() 函数打开文件,则封装在 open() 中的 syscall 触发系统调用。
- 从 MSR 寄存器找到中断函数入口,通过 swapgs 和压栈动作保存现场。
- 跳转到系统调用表,从 ax 寄存器中获取到系统调用号。
- 执行 open() 函数,按名查找对应的文件结点。
- 从 inode 表中查找对应 inode 对象,从 inode 对象查找目录块编号,根据编号找到数据块。
- 在缓存中查找该数据块对应的页,若页命中则直接返回,未命中则读取内存中的页替换掉其他页。
- 在内存中若该数据块存在则对其引用并计数,不存在则创建 inode 对象和目录块对象,并在系统文件打开表中新增 FCB。
- 最后存在则返回文件描述符 fd,不存在则返回 -1,并恢复现场。
6.2 影响性能的因素
从上述流程中可以发现影响打开文件操作性能的因素:
- CPU:进程的调度速度。
- 缓存:缓存的命中率。
- 内存:内存寻址速度。
- 磁盘:IO 读写速度。
7 总结
本文从 Linux 体系结构和计算机三大法宝入手,分析了进程管理、内存管理和虚拟文件系统管理的模型,根据打开文件的实例总结了影响性能的因素。最后感谢孟老师和李老师的辛苦付出,为我们带来了如此精品的课程,也使我更清晰地认识到了 Linux 操作系统。