Linux 内核 vs Windows 内核
Windows基本占领了电脑时代的市场,商业上取得了很大成就,但是它并不开源,所以要想接触源码得加入 Windows 的开发团队中。 对于服务器使用的操作系统基本上都是Linux,而且内核源码也是开源的,任何人都可以下载,并增加自己的改动或功能,Linux最大的魅力在于,全世界有非常多的技术大佬为它贡献代码。 操作系统核心的东西就是内核。
内核
计算机是由各种外部硬件设备组成的,比如内存、cpu、硬盘等,如果每个应用都要和这些硬件设备对接通信协议,那这样太累了,所以这个中间人就由内核来负责,让内核作为应用连接硬件设备的桥梁,应用程序只需关心与内核交互,不用关心硬件的细节。
现代操作系统,内核一般会提供8个基本能力:
现代操作系统中的内核(Kernel)是操作系统的核心组件,负责管理系统资源、提供硬件抽象、执行进程调度,以及确保系统的安全和稳定性。内核作为操作系统与硬件之间的中介,直接与硬件打交道,同时为用户态的应用程序提供服务。
内核的主要作用
进程管理
进程创建与销毁:内核负责创建和销毁进程,包括为新进程分配资源、设置初始状态等。
进程调度:内核通过调度器管理CPU的使用,决定哪个进程在何时占用CPU。调度算法如时间片轮转、优先级调度等,确保进程之间公平竞争资源。
上下文切换:当切换进程或线程时,内核负责保存和恢复CPU的上下文信息(如寄存器内容),以便正确执行不同的任务。
进程间通信 (IPC):内核提供了进程间通信的机制,如管道、消息队列、共享内存、信号等,使得进程可以安全地交换数据。
内存管理
虚拟内存管理:内核通过虚拟内存技术,让每个进程拥有独立的虚拟地址空间,避免进程之间的相互干扰,并实现更有效的内存使用。
内存分配和释放:内核管理物理内存的分配与释放,确保系统高效运行。包括页面调度、内存分页、段式管理等。
页面换入换出 (Paging/Swapping):当物理内存不足时,内核将部分不活跃的内存页交换到磁盘上,腾出空间给活跃的进程使用。
文件系统管理
文件系统接口:内核提供文件系统的统一接口,支持不同类型的文件系统(如 ext4、NTFS、FAT 等)。用户可以通过文件系统接口对文件进行读写操作,而无需关心底层的存储设备。
文件管理:内核负责文件的创建、删除、读取、写入和权限管理等操作,同时维护目录结构和文件属性(如权限、时间戳等)。
文件缓冲区管理:内核通过缓存机制提高文件 I/O 的性能,将频繁访问的数据缓存在内存中,减少磁盘 I/O 操作。
设备管理
硬件抽象:内核通过设备驱动程序为硬件设备提供抽象接口,隐藏硬件细节,让应用程序以一致的方式访问设备。
设备调度与控制:内核负责对设备的访问进行调度,确保设备的共享使用和并发访问的正确性。例如,磁盘调度算法用于优化磁盘访问的顺序。
中断处理:内核处理硬件中断,响应硬件事件(如键盘输入、网络数据到达),并执行相应的操作。中断处理程序(ISR)是内核的一部分。
网络管理
网络协议栈:内核实现了网络协议栈,如 TCP/IP 协议族,负责网络数据包的生成、传输、接收和处理。
网络设备管理:内核管理网络接口设备(如网卡),并提供接口给用户态程序进行网络通信。
网络安全与防火墙:内核可以实现网络安全机制,如防火墙规则、网络包过滤等,保护系统免受网络攻击。
安全管理
权限管理:内核管理系统资源的访问权限,确保进程只能访问它们被允许访问的资源。这包括用户和组权限、文件系统的访问控制等。
身份验证与审计:内核负责用户身份的验证(如登录时的密码验证),并记录系统事件,进行安全审计。
内存保护:内核通过内存保护机制防止进程非法访问其他进程的内存,确保系统的安全性和稳定性。
系统调用接口
系统调用:内核提供系统调用接口,允许用户态程序请求操作系统提供的服务。常见的系统调用包括文件操作(如
open、read、write)、进程控制(如fork、exec)、内存管理(如mmap)等。权限隔离:系统调用通过特权模式运行,确保应用程序无法直接操作硬件或执行危险操作,维持系统的安全性。
电源管理
节能机制:内核管理系统的电源状态,如休眠、待机等,以减少能耗并延长电池寿命。特别是在移动设备上,电源管理尤为重要。
设备电源控制:内核可以控制设备的电源状态,关闭未使用的设备,减少系统能耗。 内核是怎么工作的? 内核具有很高的权限,可以控制cpu、内存、硬盘等硬件,而应用程序具有的权限很小,因此大多数操作系统,把内存分成了两个区域:
内核空间,这个内存空间只有内核程序可以访问;
用户空间,这个内存空间专门给应用程序使用; **用户空间的代码只能访问一个局部的内存空间,而内核空间的代码可以访问所有内存空间。**因此,当程序使用用户空间时,我们常说该程序在用户态执行,而当程序使内核空间时,程序则在内核态执行。 应用程序如果需要进入内核空间,就需要通过系统调用,下面来看看系统调用的过程:
内核程序执行在内核态,用户程序执行在用户态。当应用程序使用系统调用时,会产生一个中断。发生中断后,CPU会中断当前在执行的用户程序,转而跳转到中断处理程序,也就是开始执行内核程序。内核处理完后,主动触发中断,把CPU执行权限交回给用户程序,回到用户态继续工作。
Linux 的设计
一位名叫Linus Torvalds的芬兰小伙子,他在1991年用C语言写出了第一版的Linux操作系统,那年他 22岁。 Linux 内核设计的理念主要有这几个点:
MultiTask,多任务
SMP,对称多处理
ELF,可执行文件链接格式
Monolithic Kernel,宏内核
MultiTask
MultiTask的意思是多任务,代表着Linux是一个多任务的操作系统。 多任务意味着可以有多个任务同时执行,这里的「同时」可以是并发或并行:
对于单核CPU时,可以让每个任务执行一小段时间,时间到就切换另外一个任务,从宏观角度看,一段时间内执行了多个任务,这被称为并发。
对于多核CPU时,多个任务可以同时被不同核心的CPU同时执行,这被称为并行。
SMP
SMP的意思是对称多处理,代表着每个CPU的地位是相等的,对资源的使用权限也是相同的,多个CPU共享同一个内存,每个CPU都可以访问完整的内存和硬件资源。 这个特点决定了Linux操作系统不会有某个CPU单独服务应用程序或内核程序,而是每个程序都可以被分配到任意一个CPU上被执行。
ELF
编译器编译源代码后生成的文件叫做目标文件,而目标文件经过编译器链接之后得到的就是可执行文件。
目标文件就是源代码经过编译后但未进行链接的那些中间文件,它与可执行文件的格式非常相似,所以一般跟可执行文件格式一起采用同一种格式存储。除了可执行文件外,动态链接库(DDL,Dynamic Linking Library)、静态链接库(Static Linking Library) 均采用可执行文件格式存储。
ELF文件的基本结构,其主要由四部分组成:
ELF Header
ELF Program Header Table (或称Program Headers、程序头)
ELF Section Header Table (或称Section Headers、节头表)
ELF Sections
ELF Header
使用readelf工具来查看ELF Header.
readelf -h hello.o
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: REL (Relocatable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 672 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 64 (bytes)
Number of section headers: 13
Section header string table index: 10
ELF文件结构示意图中定义的Elf_Ehdr的各个成员的含义与readelf具有对应关系。 | 成员 | 含义 | | — | — | | e_ident | Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 | | | Class: ELF32 | | | Data: 2’s complement, little end | | | Version: 1(current) | | | OS/ABI: UNIX - System V | | | ABI Version: 0 | | e_type | Type: REL (Relocatable file) | | | ELF文件类型 | | e_machine | Machine: Advanced Micro Devices X86-64 | | | ELF文件的CPI平台属性 | | e_version | Version: 0x1 | | | ELF版本号。一般为常数1 | | e_entry | Entry point address: 0x0 | | | 入口地址,规定ELF程序的入口虚拟地址,操作系统在加载完该程序后从这个地址开始执行进程的指令。可重定位指令一般没有入口地址,则该值为0 | | e_phoff | Start of program headers: 0(bytes into file) | | e_shoff | Start of section headers: 672 (bytes into file) | | | Section Header Table 在文件中的偏移 | | e_word | Flags: 0x0 | | | ELF标志位,用来标识一些ELF文件平台相关的属性。 | | e_ehsize | Size of this header: 64 (bytes) | | | ELF Header本身的大小 | | e_phentsize | Size of program headers: 0 (bytes) | | e_phnum | Number of program headers: 0 | | e_shentsize | Size of section headers: 64 (bytes) | | | 单个Section Header大小 | | e_shnum | Number of section headers: 13 | | | Section Header的数量 | | e_shstrndx | Section header string table index: 10 | | | Section Header字符串表在Section Header Table中的索引 | ELF结构
Monolithic Kernel
Monolithic Kernel的意思是宏内核,Linux内核架构就是宏内核,意味着Linux的内核是一个完整的可执行程序,且拥有最高的权限。
宏内核的特征是系统内核的所有模块,比如进程调度、内存管理、文件系统、设备驱动等,都运行在内核态。
不过,Linux 也实现了动态加载内核模块的功能,例如大部分设备驱动是以可加载模块的形式存在的,与内核其他模块解藕,让驱动开发和驱动加载更为方便、灵活。
与宏内核相反的是微内核,微内核架构的内核只保留最基本的能力,比如进程调度、虚拟机内存、中断等,把一些应用放到了用户空间,比如驱动程序、文件系统等。这样服务与服务之间是隔离的,单个服务出现故障或者完全攻击,也不会导致整个操作系统挂掉,提高了操作系统的稳定性和可靠性。
微内核内核功能少,可移植性高,相比宏内核有一点不好的地方在于,由于驱动程序不在内核中,而且驱动程序一般会频繁调用底层能力的,于是驱动和硬件设备交互就需要频繁切换到内核态,这样会带来性能损耗。华为的鸿蒙操作系统的内核架构就是微内核。
还有一种内核叫混合类型内核,它的架构有点像微内核,内核里面会有一个最小版本的内核,然后其他模块会在这个基础上搭建,然后实现的时候会跟宏内核类似,也就是把整个内核做成一个完整的程序,大部分服务都在内核中,这就像是宏内核的方式包裹着一个微内核。
Windows 设计
当今 Windows 7、Windows 10 使用的内核叫 Windows NT,NT 全称叫 New Technology。
下图是 Windows NT 的结构图片:
Windows 和 Linux 一样,同样支持 MultiTask 和 SMP,但不同的是,Window 的内核设计是混合型内核在上图你可以看到内核中有一个 MicroKernel 模块,这个就是最小版本的内核,而整个内核实现是一个完整的程序,含有非常多模块。
Windows 的可执行文件的格式与 Linux 也不同,所以这两个系统的可执行文件是不可以在对方上运行的.
Windows 的可执行文件格式叫 PE,称为可移植执行文件,扩展名通常是.exe、.dll、.sys等。
PE 的结构你可以从下图中看到,它与 ELF 结构有一点相似。
