计算机基础

计算机系统:操作系统内核

1、什么是内核


​说到操作系统,就必须说内核。内核是操作系统中应用连接硬件设备的桥梁。

内核仅仅是操作系统的一部分,是真正与硬件交互的那部分软件,与硬件交互包括读写硬盘、读写网盘、读写内存,以及任何连接到系统中的硬件。

除了与硬件交互外,内核还负责分配资源,分配什么资源呢?所谓资源就是硬件,比如CPU时间、内存、IO等等,这些都是资源。

1.1、内核的能力

对于一个现代的操作系统来说,它的内核至少应该提供以下 4 种基本能力:

  • 管理进程、线程(决定哪个进程、线程使用 CPU);
  • 管理内存(决定内存用来做什么);
  • 连接硬件设备(为进程、和设备间提供通信能力);
  • 提供系统调用(接收进程发送来的系统调用并执行)。

1.2、操作系统分层

从上面 4 种能力来看操作系统和内核之间的关系,通常可以把操作系统分成 3 层

  • 最上层的应用(Applications)
  • 中间的内核(Kernel)
  • 最底层的硬件设备抽象(CPU、Memory,Devices)

1.3、内核是如何工作的

​内核权限非常高,它可以管理进程、可以直接访问所有的内存,因此确实需要和进程之间有一定的隔离。这个隔离用类似请求/响应的模型,非常符合常理。

为了帮助理解什么是内核,请你先思考一个问题:进程和内核的关系,是不是像浏览器请求服务端服务

内核权限非常高,它可以管理进程、可以直接访问所有的内存,因此确实需要和进程之间有一定的隔离。这个隔离用类似请求/响应的模型,如下图所示。

但不同的是在浏览器、服务端模型中,浏览器和服务端是用不同的机器在执行,因此不需要共享一个 CPU。但是在进程调用内核的过程中,这里是存在资源共享的

  • 比如,一个机器有 4 个 CPU,不可能让内核用一个 CPU,其他进程用剩下的 CPU。这样太浪费资源了。
  • 再比如,进程向内核请求 100M 的内存,内核把 100M 的数据传回去。 这个模型不可行,因为传输太慢了。

所以,这里多数操作系统的设计都遵循一个原则:进程向内核发起一个请求,然后将 CPU 执行权限让出给内核。内核接手 CPU 执行权限,然后完成请求,再转让出 CPU 执行权限给调用进程。

用户态和内核态

​内核(Kernel) 运行在超级权限模式(Supervisor Mode)下,所以拥有很高的权限。按照权限管理

的原则,多数应用程序应该运行在最小权限下。因此,很多操作系统,将内存分成了两个区域:

  • 内核空间(Kernal Space),这个空间只有内核程序可以访问;
  • 用户空间(User Space),这部分内存专门给应用程序使用。

​用户空间中的代码被限制了只能使用一个局部的内存空间,我们说这些程序在用户态(User Mode) 执行。内核空间中的代码可以访问所有内存,我们称这些程序在内核态(Kernal Mode) 执行。

系统调用过程

如果用户态程序需要执行系统调用,就需要切换到内核态执行。下面我们来讲讲这个过程的原理。

如上图所示:内核程序执行在内核态(Kernal Mode),用户程序执行在用户态(User Mode)。当发生系统调用时,用户态的程序发起系统调用。因为系统调用中牵扯特权指令,用户态程序权限不足,因此会中断执行,也就是 Trap(Trap 是一种中断)。

发生中断后,当前 CPU 执行的程序会中断,跳转到中断处理程序。内核程序开始执行,也就是开始处理系统调用。内核处理完成后,主动触发 Trap,这样会再次发生中断,切换回用户态工作。

2、Linux 系统


Linux 内核设计的理念主要有这几个点:

  • MultiTask,多任务
  • SMP(Symmetric multiprocessing),多任务
  • ELF(Executable and Linkable Format),可执行文件链接格式
  • Monolithic Kernel,宏内核

2.1、MultiTask

MultiTask 指多任务,Linux 是一个多任务的操作系统。多任务就是多个任务可以同时执行,这里的“同时”并不是要求并发,而是在一段时间内可以执行多个任务。这里的 “同时“ 以是并发或并行:

  • 对于单核 CPU 时,可以让每个任务执行一小段时间,时间到就切换另外一个任务,从宏观角度看,一段时间内执行了多个任务,这被称为并发。
  • 对于多核 CPU 时,多个任务可以同时被不同核心的 CPU 同时执行,这被称为并行。

2.2、SMP(Symmetric multiprocessing)

SMP 指对称多处理。其实是说 Linux 下每个处理器的地位是相等的,内存对多个处理器来说是共享的,每个处理器都可以访问完整的内存和硬件资源

​ 这个特点决定了在 Linux 上不会存在一个特定的处理器处理用户程序或者内核程序,它们可以被分配到任何一个处理器上执行。

2.3、ELF(Executable and Linkable Format)

ELF的意思是可执行文件链接格式,这是一种从 Unix 继承而来的可执行文件的存储格式。可以从下图看到它的结构:

  • 程序头表(Program header table):描述 0 个或多个内存段信息
  • 分段头表(Section header table):描述 0 段或多段链接与重定位需要的数据
  • 程序头表与分段头表引用的数据 (Sections):在ELF文件中,数据和代码分开存放,这样可以按照其功能属性分成一些区域,比如程序,数据,符号表等。这些分离存放的区域在ELF文件中反映成section。ELF文件中典型的节如下
  • .text .text节是保存了程序代码指令的代码节(已编译程序的二进制代码)。一段可执行程序,如果存在Phdr,则.text节就会存在于.text段中。由于.text节保存了程序代码,所以节类型SHT_PROGBITS。
  • .rodata rodata节保存了只读的数据,如一行C语言代码中的字符串,常量。由于.rodata节是只读的,所以只能存在于一个可执行文件的只读段中。因此,只能在text段(不是data段)中找到.rodata节。由于.rodata节是只读的,所以节类型为SHT_PROGBITS。
  • .data .data节存在于data段中,其保存了初始化的全局变量,静态变量等数据。由于.data节保存了程序的变量数据,所以节类型为SHT_PROGBITS。
  • .bss .bss节存在于data段中,占用空间不超过4字节,仅表示这个节本省的空间。.bss节保存了未进行初始化的全局数据(未初始化的全局变量和静态变量)。程序加载时数据被初始化为0,在程序执行期间可以进行赋值。由于.bss节未保存实际的数据,所以节类型为SHT_NOBITS。
  • .sysmtab .symtab节是一个ElfN_Sym的数组,即符号表,存放了程序中定义和引用的函数和全局变量的信息,节类型为SHT_SYMTAB。
  • .debug 调试符号表,它需要以’-g’选项编译才能得到,里面保存了程序中定义的局部变量和类型定义,程序中定义和引用的全局变量,以及原始的C文件
  • .line 原始的C文件行号和.text节中机器指令之间的映射
  • .strtab .strtab节保存的是符号字符串表,内容包括.symtab和.debug节中的符号表。节类型为SHT_STRTAB。

2.4、Monolithic Kernel

Monolithic Kernel意思是宏内核,宏内核反义词就是 Microkernel ,微内核的意思。

Linux 是宏内核架构,这说明 Linux 的内核是一个完整的可执行程序,且内核用最高权限来运行。

​宏内核的特点:就是有很多程序会打包在内核中,比如,文件系统、驱动、内存管理等。当然这并不是说,每次安装驱动都需要重新编译内核,现在 Linux 也可以动态加载内核模块。所以哪些模块在内核层,哪些模块在用户层,这是一种系统层的拆分,并不是很强的物理隔离。

与宏内核对应,接下来说说微内核,内核只保留最基本的能力。比如进程调度、虚拟内存、中断。多数应用,甚至包括驱动程序、文件系统,是在用户空间管理的。这样服务与服务之间是隔离的,单个服务出现故障或者完全攻击,也不会导致整个操作系统挂掉,提高了操作系统的稳定性和可靠性。

​ 微内核内核功能少,可移植性高,相比宏内核有一点不好的地方在于,由于驱动程序不在内核中,而且驱动程序一般会频繁调用底层能力的,于是驱动和硬件设备交互就需要频繁切换到内核态,这样会带来性能损耗。华为的鸿蒙操作系统的内核架构就是微内核。

还有一种内核叫混合类型内核,它的架构有点像微内核,内核里面会有一个最小版本的内核,然后其他模块会在这个基础上搭建,然后实现的时候会跟宏内核类似,也就是把整个内核做成一个完整的程序,大部分服务都在内核中,这就像是宏内核的方式包裹着一个微内核。

3、Window 系统


​Windows 和 Linux 的设计有很大程度的相似性。Windows也有内核,它的内核是 C/C++ 写的。准确地说,Windows 有两个内核版本。一个是早期的Windows 9x 内核,早期的 Win95, Win98 都是这个内核。我们今天用的 Windows 7, Windows 10 是另一个内核,叫作 Windows NT。NT 指的是 New Technology。接下来我们讨论的都是 NT 版本的内核。

下图是Windows 内核架构的图:

​Windows 同样支持 Multitask 和 SMP(对称多处理)。Windows 的内核设计属于混合类型。你可以看到内核中有一个 Microkernel 模块。而整个内核实现又像宏内核一样,含有的能力非常多,是一个完整的整体。

​ Windows 下也有自己的可执行文件格式,这个格式叫作 Portable Executable(PE),也就是可移植执行文件,扩展名通常是.exe.dll.sys等。

​PE 文件的结构和 ELF 结构有很多相通的地方,我找到了一张图片帮助你更直观地理解。 因为这部分知识涉及编译原理,我这里就不详细介绍了,感兴趣同学可以在留言区和大家一起讨论,或者查阅更多资料。

Windows 还有很多独特的能力,比如 Hyper-V 虚拟化技术,有关虚拟化技术在之后讲解。

总结:


对于内核的架构一般有这三种类型:

  • 宏内核,包含多个模块,整个内核像一个完整的程序,内核大(宏内核),方便优化性能,毕竟内核更了解计算机中的资源。
  • 微内核,有一个最小版本的内核,一些模块和服务则由用户态管理;内核很小(微内核)方便移植,因为体积小、安装快;
  • 混合内核,是宏内核和微内核的结合体,内核中抽象出了微内核的概念,也就是内核中会有一个小型的内核,其他模块就在这个基础上搭建,整个内核是个完整的程序;

Linux 的内核设计是采用了宏内核,Window 的内核设计则是采用了混合内核。

这两个操作系统的可执行文件格式也不一样, Linux 可执行文件格式叫作 ELF,Windows 可执行文件格式叫作 PE。

问题:Linux 内核和 Windows 内核有什么区别?


Windows 有两个内核,最新的是 NT 内核,目前主流的 Windows 产品都是 NT 内核。NT 内核和 Linux 内核非常相似,没有太大的结构化差异。

从整体设计上来看,Linux 是宏内核,NT 内核属于混合型内核。和微内核不同,宏内核和混合类型内核从实现上来看是一个完整的程序。只不过混合类型内核内部也抽象出了微内核的概念,从内核内部看混合型内核的架构更像微内核。

另外 NT 内核和 Linux 内核还存在着许多其他的差异,比如:

  • Linux 内核是一个开源的内核;
  • 它们支持的可执行文件格式不同;
  • 它们用到的虚拟化技术不同。