目录
Linux核心概念学习笔记
一、Linux内核架构
(一)内核的任务
从纯技术层面看,Linux内核处于硬件与软件之间,是连接二者的中间层,负责将应用程序的请求传递给硬件,同时充当底层驱动程序,对系统中的各类设备和组件进行寻址。从应用程序的视角出发,内核可看作是一台增强的计算机,将计算机抽象到一个高层次,应用程序仅与内核有联系,内核是应用程序所认知的层次结构中的最底层。当多个程序在同一系统中并发运行时,内核又扮演着资源管理程序的角色,负责将可用的共享资源分配给各个系统进程,同时保证系统的完整性。此外,内核还能视为一个库,提供了一组面向系统的命令,通常通过系统调用向计算机发送请求。
(二)实现策略
在操作系统的实现方面,主要有微内核和宏内核两种泛型。
-
微内核:仅最基本的功能由内核直接实现,像文件系统、内存管理等其他功能都委托给一些独立的进程,这些进程通过明确定义的通信接口与内核通信。其优点是具有动态可扩展性和在运行时切换重要组件的能力,但由于各组件之间复杂通信需要额外的CPU时间,所以在使用性方面进展不大。
-
宏内核:这是构建系统内核的传统方法,内核的全部代码包括所有子系统(如内存管理、文件系统、设备驱动程序)都打包在一个文件中,内核中的每个函数都能访问内核的所有其他部分,这容易导致源代码中出现复杂的嵌套。当前,Linux采用的是宏内核的设计模式,并进行了一定程度的改进,在系统运行中,模块可以插入到内核代码中,也可以移除。
(三)内核的组成部分
Linux内核包含多个重要的子系统,共同协作实现系统的各项功能。
- 进程管理与调度子系统(process scheduler):是Linux内核中最重要的子系统之一,主要负责对CPU资源的访问控制。由于计算机中的CPU资源有限,而众多应用程序都需要使用CPU资源,所以需要进程调度子系统对CPU进行调度管理,让各个进程能够以尽量公平的方式访问CPU。该子系统包含4个子模块:
- scheduling policy:实现进程调度的策略,决定哪个(或哪几个)进程将获得CPU使用权。
- architecture - specific schedulers:体系结构相关的部分,将对不同CPU的控制抽象为统一的接口,主要在暂停(suspend)和恢复(resume)进程时使用,涉及CPU的寄存器访问、汇编指令操作等。
- architecture - independent scheduler:体系结构无关的部分,与“scheduling policy模块”沟通,决定接下来要执行的进程,然后通过“architecture - specific schedulers模块”恢复指定的进程。
- system call interface:系统调用接口,进程调度子系统通过此接口将需要提供给用户空间的接口开放出去,同时屏蔽掉不需要用户空间程序关心的细节。
- 图片链接:进程调度子系统模块示意图
- 内存管理子系统(memory manager, mm):同样是Linux内核中的重要子系统,负责对内存资源的访问控制。Linux系统会在硬件物理内存和进程所使用的虚拟内存之间建立映射关系,这种映射以进程为单位,不同的进程可以使用相同的虚拟内存,而这些相同的虚拟内存可以映射到不同的物理内存上。内存管理子系统包含3个子模块:
- architecture - specific managers:体系结构相关部分,提供用于访问硬件内存的虚拟接口。
- architecture - independent manager:体系结构无关部分,提供所有的内存管理机制,包括以**进程为单位的内存映射、虚拟内存的交换(swapping)**等。
- system call interface:系统调用接口,通过该接口向用户空间的应用程序**提供内存的分配、释放,文件的映射(map)**等功能。
- 图片链接:内存管理子系统模块示意图
- 虚拟文件系统(virtual file system, VFS):传统意义上的文件系统是存储和组织计算机数据的方法,它将计算机磁盘、硬盘等设备上的数据块以易懂、人性化的文件和目录结构形式抽象出来,方便查找和访问。随着计算机技术的发展,出现了多种类型的文件系统,为了兼容,操作系统或内核需要以相同的表现形式同时支持多种类型的文件系统,这就引出了虚拟文件系统(VFS)的概念。VFS的功能是管理各种各样的文件系统,屏蔽它们的差异,以统一的方式为用户程序提供访问文件的接口。VFS子系统包含6个子模块:
- device drivers:设备驱动,用于控制所有的外部设备及控制器。由于存在大量不能相互兼容的硬件设备,所以设备驱动的数量众多,Linux内核中将近一半的源代码都是设备驱动。
- device - independent interface:该模块定义了描述硬件设备的统一方式(统一设备模型),所有的设备驱动都遵守这个定义,降低了开发难度,同时可以用一致的形式向上提供接口。
- logical systems:每一种文件系统都对应一个logical system(逻辑文件系统),它会实现具体的文件系统逻辑。
- 图片链接:虚拟文件系统子系统模块示意图
- 网络子系统(network):负责管理系统的网络设备,并实现多种多样的网络标准,使系统能够进行网络通信。
- 进程间通信子系统(ipc, inter - process communication):该子系统不管理任何硬件,主要负责Linux系统中进程之间的通信,实现进程间的数据交换和同步。
(四)内核源文件目录结构
二、Linux文件系统
(一)文件系统架构
Linux文件系统的架构分为用户空间、内核空间和硬件3个部分。
- 用户空间层面:应用程序使用 glibc库封装的标准I/O流函数访问文件 ,如fopen(打开)、fclose(关闭)、fread(读取)、fwrite(写入)、fseek(设置文件偏移)等。
- 硬件层面:外部存储设备包括块设备、闪存、NVDIMM设备等。
- 内核空间层面:由于内核支持多种文件系统类型,为了给用户提供统一的操作接口,内核实现了一个抽象层——虚拟文件系统(VFS)。常见的文件系统类型有:
- 块设备文件系统:适用于机械硬盘和固态硬盘等块设备,常用的有EXT和btrfs。
- 闪存文件系统:存储设备为NAND闪存和NOR闪存,常用的有JFFS2、UBIFS。
- 内存文件系统:常用的是tmpfs。
- 伪文件系统:为了使用虚拟文件系统的编程接口,常用的有sockfs、proc、sysfs、hugetlbfs、cgroup等。
- 图片链接:Linux文件系统架构图
(二)虚拟文件系统的数据结构
- 超级块(super block):文件系统的开始部分,描述文件系统的总体信息,挂载文件系统时,内存中会创建结构体super_block。
- 索引节点(inode):每个文件对应一个索引节点,每个索引节点有唯一编号。当内核访问存储设备上的文件时,会在内存中创建索引节点的结构体inode。
- 目录项(dentry):当内核访问存储设备上的一个目录项时,会在内存中创建该目录项的一个副本——结构体dentry。
- 文件结构体(file):当进程打开一个文件时,VFS就会创建文件的一个file结构体,然后为文件表中分配一个文件描述符,最后把文件描述符和file结构体的映射添加到打开文件表中。
三、Linux进程管理
(一)进程相关概念
- 进程:传统上UNIX操作系统下运行的应用程序、服务器及其他程序都称为进程。每个进程都在CPU的虚拟内存中分配地址空间,各个进程的地址空间是完全独立的。Linux是多任务系统,支持并发执行的若干进程,系统中同时真正在运行的进程数目最多不超过CPU的数目。
- 进程切换:进程之间的切换由内核借助CPU的帮助完成技术细节。在撤销进程的CPU资源之前,内核会保存进程所有与状态相关的要素,并将进程置于空闲状态。重新激活进程时,将保存的状态原样恢复。
- 调度:内核必须确定如何在现存进程之间共享CPU时间,重要进程得到的CPU时间多一些,次要进程少一些,确定哪个进程运行多长时间的过程称为调度。
(二)进程的层次结构
Linux对进程采用了一种层次系统,每个进程都依赖于一个父进程。内核启动init程序作为第一个进程,负责进一步系统初始化工作,init是进程树的根,所有进程都直接或间接起源于该进程(在linux系统终端输入pstree查看进程树)。
(三)新进程创建机制
UNIX操作系统中创建新进程的机制有两个,分别是fork和exec。
- fork:可以创建当前进程的一个副本,除了进程ID(PID),子进程完全复制父进程的内存内容。在Linux中,采用写时复制(copy on write)技术,将内存复制操作延迟到父进程或子进程向某内存页面写入数据之前,在只读访问的情况下父进程和子进程共用一个内存页,提高了执行效率。
- exec:将一个新程序加载到当前进程的内存中并执行,旧程序的内存页被刷出,其内容替换为新数据,开始执行新程序。
(四)线程
线程有时也称为轻量级进程,本质上一个进程可能由若干线程组成,这些线程共享同样的数据和资源,但可能执行程序中不同的代码路径。Linux用clone方法创建线程,工作方式类似于fork,但是会检查确认哪些资源与父进程共享,哪些资源为线程独立创建。细粒度的资源分配扩展了一般线程的概念,在一定程度上允许线程与进程之间的连续转换。
(五)命名空间
传统的Linux使用了许多全局量,启用命名空间后,以前的全局资源具有了不同的分组。每个命名空间可以包含一个特定的PID集合,或可以提供文件系统的不同视图,在某个命名空间中挂载的卷不会传播到其他命名空间中。命名空间的经典作用之一是可以通过称为容器的命名空间来建立系统的多个视图,一台物理机中可以运行多个虚拟机。与完全的虚拟解决方案(如KVM)相比,计算机上多了一个内核来管理所有的容器。