当你打开应用程序、播放视频或保存文档时,计算机需要协调许多不同的活动。程序需要处理器时间、内存、文件,以及对各种设备的访问。
在上一篇教程中,我们介绍了操作系统:它负责管理计算机资源,并为应用程序提供通用服务。
而在操作系统的核心位置,就是内核(Kernel)。
那么,内核究竟是什么?它与操作系统有什么区别?应用程序为什么需要它?下面,我们一起认识这层关键的软件。
1. 什么是内核?
内核是操作系统的核心部分,负责管理基本资源,并控制软件与硬件之间的重要交互。
内核本身也是软件,由 CPU 执行的一系列指令组成。CPU 是中央处理器,负责执行程序指令。内核并不是计算机内部的一块独立芯片。
内核帮助决定哪些任务可以获得处理器时间,管理程序对内存的访问,并为程序使用文件、设备等资源提供受控的途径。
假设浏览器、音乐播放器和文本编辑器正在同时运行。它们各自执行不同的任务,却需要共享同一台计算机的资源。
内核负责协调这种共享,同时防止应用程序随意干扰彼此。
2. 内核不等于整个操作系统
“内核”和“操作系统”关系密切,但并不完全相同。
一个完整的操作系统通常包括内核,以及系统服务、程序库、命令行工具等软件,有些还包含图形桌面。
系统服务是在后台执行特定工作的程序,例如管理网络连接。程序库则是可以供其他程序调用的可复用代码。
内核为这些软件中的许多功能提供基础支持。
Linux 就是一个很好的例子。严格来说,Linux 是一个内核。Ubuntu、Debian 等 Linux 发行版,则把 Linux 内核与工具、程序库及其他软件组合起来,形成可以实际使用的操作系统。
因此,你看到的桌面并不是内核,输入命令的终端窗口也不是内核。这些界面帮助你与软件交互,而这些软件最终会依赖内核提供的服务。
3. 应用程序为什么需要内核?
想象一下,如果每个应用程序都能随意修改任何内存位置、重新配置设备,或者独占处理器,会发生什么?
一个程序的错误可能破坏另一个程序的数据。两个应用程序可能向同一个设备发送互相冲突的命令。恶意程序甚至可能修改关键的系统信息。
内核提供了统一协调资源访问、执行规则的地方。
应用程序通常通过规定好的接口请求操作系统服务,而不是各自随意控制硬件。
例如,文本编辑器可以请求把数据写入文件,而不需要了解每一种存储设备的具体控制命令。
这种设计既提供了保护,也提供了抽象(Abstraction)。
抽象是指用较简单的接口隐藏底层细节。文件就是一个常见例子:应用程序处理的是一组有名称的数据,而不需要自行管理这些数据在存储设备上的物理位置。
4. 内核管理 CPU 时间
一个正在运行的程序,会以**进程(Process)**的形式被操作系统管理。进程包含程序使用的内存,以及操作系统管理它所需的信息等资源。
进程内部的线程(Thread),是一条可以被调度执行的指令序列。一个进程可以包含一个线程,也可以包含多个线程。
内核中的**调度器(Scheduler)**负责选择哪个已经准备好运行的线程获得 CPU 时间。
CPU 的**核心(Core)**是处理器内部执行指令的单元。多个核心让多个线程能够同时运行,而调度机制则让更多线程共享有限的执行资源。
假设浏览器正在等待网络数据。操作系统可以让另一个已经准备好的线程运行,而不是让处理器闲着。
当执行从一个线程切换到另一个线程时,系统会保存恢复原线程所需的信息,并恢复下一个线程运行所需的信息。这个过程称为上下文切换(Context Switch)。
通过调度,内核让多个程序持续推进工作,同时帮助计算机保持响应能力。
5. 内核管理和保护内存
应用程序需要内存来保存指令和数据。
内核跟踪物理内存的使用情况,并管理进程如何通过地址映射使用这些内存。
现代通用操作系统采用虚拟内存(Virtual Memory)。它让每个进程拥有自己的内存地址视图,而不是把全部物理内存直接暴露给程序。
处理器中的内存管理硬件,会根据操作系统维护的信息,把虚拟地址转换为物理地址。
这种机制也支持内存保护。一个进程通常不能在未经许可的情况下访问另一个进程的私有内存。
例如,文本编辑器中的错误,不应该让它覆盖浏览器的私有数据或关键的内核信息。
内核和处理器硬件共同维护这些边界:内核建立地址映射并设置权限,硬件则在访问内存时检查这些规则。
6. 内核帮助程序使用文件和设备
应用程序经常需要使用文件、网络连接、键盘、显示器和存储设备。
**文件系统(File System)**是用于在存储设备上组织文件和目录的一套规则与数据结构。
**设备驱动程序(Device Driver)**是知道如何与某种设备或某类设备通信的软件。
在许多操作系统中,文件系统代码和大量设备驱动程序作为内核的一部分运行。另一些设计则把其中某些组件放在独立进程中运行。
无论采用哪种设计,应用程序都可以使用通用接口,而不必自己实现各种硬件的控制细节。
例如,程序请求读取文件数据时,系统会检查访问权限、定位所需数据,并安排必要的设备操作。
即使不同计算机使用不同的存储硬件,应用程序仍然可以通过标准接口获得数据。
7. 用户态与内核态
内核需要拥有普通应用程序不应该拥有的权限。
现代处理器支持不同权限的执行模式,其中两个重要概念是用户态(User Mode)和内核态(Kernel Mode)。
用户态是一种受到限制的执行模式,普通应用程序代码通常在这种模式下运行。内核态是一种拥有较高权限的执行模式,用于运行可信的操作系统代码。
特权操作是只允许可信代码执行的操作,例如修改某些处理器设置,或配置内存保护机制。
应用程序不能自行决定获得这些权限。处理器会强制执行进入特权模式的规则。
这也解释了为什么一个应用程序崩溃后,计算机往往还能继续运行,而严重的内核故障却可能让整个系统停止工作。
内核拥有更大的权限,因此其中的错误可能造成更广泛的影响。
需要注意,内核态是处理器的一种执行模式,不是一颗独立的处理器。同一个 CPU 可以先在用户态执行应用程序代码,再切换到内核态执行内核代码。
8. 应用程序如何请求内核服务?
如果应用程序只能在受限权限下运行,它们如何打开文件,或请求其他受保护的服务?
答案是系统调用(System Call)。
系统调用是一种受控机制,程序通过它向内核请求服务。例如,打开文件、读取数据、创建进程,或者通过网络进行通信。
应用程序经常通过程序库中的函数发起系统调用。这些函数可以准备请求,并完成进入内核所需的步骤。
不过,并不是每一次函数调用都是系统调用。两个数字相加,或者搜索已经位于内存中的数据,都可以完全在应用程序内部完成。
发生系统调用时,处理器把执行转移到规定好的内核入口。内核检查请求,执行被允许的操作,然后返回结果。
这是一个受控的入口,并不意味着应用程序可以随意使用内核的全部权限。
另外,进入内核不一定意味着切换到另一个进程。内核可能处理完请求后,就直接返回原来的应用程序。
9. 示例:程序读取文件
下面用一个简单例子,把这些概念连接起来。
假设文本编辑器想从一个已经打开的文件中读取部分内容。
首先,它调用请求文件数据的函数。这个请求通过系统调用进入内核。
内核检查请求是否有效,以及这个已打开的文件是否允许读取。
接下来,内核判断所需数据是否已经位于内存中。操作系统经常把最近使用的文件数据保存在**缓存(Cache)**里。缓存是临时保存数据的区域,可以减少重复进行较慢访问的需要。
如果数据已经在缓存中,内核可能不需要读取存储设备,就能完成请求。
如果数据不在缓存中,系统就会通过相关驱动程序安排存储操作。文本编辑器等待期间,调度器可以让其他线程运行。
数据准备好后,系统将其提供给文本编辑器,读取操作随后返回。
编辑器便可以解析文档内容,并将其显示出来。
因此,一个看似简单的读取操作,背后可能涉及系统调用、权限检查、内存、文件系统代码、设备驱动程序和线程调度。
10. 内核如何响应硬件?
应用程序并不是内核工作的唯一来源,硬件也需要系统响应。
**中断(Interrupt)**是一种信号,可以让处理器暂时转去执行处理某个事件的代码。
例如,设备可能通过中断通知系统:某项操作已经完成。定时器中断则可以帮助操作系统跟踪时间,并作出调度决策。
响应事件的代码称为中断处理程序。它负责处理事件,或安排后续工作。
借助中断,系统可以及时响应硬件事件,而不需要应用程序不断检查每一个设备。
系统调用和硬件中断的起点不同:系统调用是应用程序主动请求服务,而硬件中断是硬件发出事件信号。
这两种情况都可能让处理器开始执行内核代码。
11. 内核不会代替应用程序执行每一条指令
我们很容易把内核想象成一个中间人,认为应用程序的每一条指令都必须经过它。
实际运行方式并不是这样。
应用程序的指令通常直接在 CPU 上以用户态执行。算术运算、比较操作,以及权限允许的内存访问,都不需要内核逐条批准。
内核负责建立运行环境、管理资源,并在需要时介入。
这种介入可能由系统调用、中断或**异常(Exception)**触发。异常是处理器在执行指令过程中报告的某种情况,例如非法内存访问。
这种配合让系统既高效又可控:应用程序直接执行自己的指令,处理器与内核则共同维护重要的保护边界。
12. 总结
内核是让计算机能够有序共享资源的核心软件层。
它负责调度线程、管理内存、执行保护规则,并提供帮助程序使用文件和设备的基本服务。
应用程序通常直接在 CPU 上执行自己的指令。当它们需要受保护的服务时,会通过受控接口进入内核。
理解这种关系,是进一步学习操作系统工作原理的重要基础。
在下一篇教程中,我们将进一步介绍用户态与内核态:处理器如何区分普通应用程序代码与拥有特权的操作系统代码,以及执行过程如何在两者之间安全切换。
