操作系统的体系结构是一个开放的问题。操作系统在核心态为应用程序提供公共的服务,那么操作系统在核心态应该提供什么服务、怎样提供服务?有关这个问题的回答形成了两种主要的体系结构:宏内核和微内核。
宏内核:大而全
宏内核系统将操作系统的主要功能模块都作为一个紧密联系的整体运行在核心态,从而为应用提供高性能的系统服务。因为各管理模块之间共享信息,能有效利用相互之间的有效特性,所以具有无可比拟的性能优势。
特点
- 性能优越:由于宏内核的各个功能模块直接运行在核心态,因此它们之间的通信和调度开销较小,可以获得较高的性能。
- 简单高效:宏内核的设计相对简单,模块之间的交互直接,易于实现和调试。
- 扩展性差:由于所有模块都运行在核心态,因此新功能的引入或修改需要对整个内核进行修改和重新编译,扩展性较差。
但随着体系结构和应用需求的不断发展,需要操作系统提供的服务越来越多,而且接口形式越来越复杂,操作系统的设计规模也急剧增长,操作系统也面临着“软件危机”困境。为此,操作系统设计人员试图按照复杂性、时间常数、抽象级别等因素,将操作系统内核分成基本进程管理、虚存、I/O与设备管理、IPC、文件系统等几个层次,继而定义层次之间的服务结构,提高操作系统内核设计上的模块化。但是由于层次之间的交互关系错综复杂,定义清晰的层次间接口非常困难,复杂的交互关系也使得层次之间的界限极其模糊。
微内核:小而美
为解决操作系统的内核代码难以维护的问题,于是提出了微内核的体系结构。它将内核中最基本的功能(如进程管理等)保留在内核,而将那些不需要在核心态执行的功能移到用户态执行,从而降低了内核的设计复杂性。而那些移出内核的操作系统代码根据分层的原则被划分成若干服务程序,它们的执行相互独立,交互则都借助于微内核进行通信。
微内核结构有效地分离了内核与服务、服务与服务,使得它们之间的接口更加清晰,维护的代价大大降低,各部分可以独立地优化和演进,从而保证了操作系统的可靠性。微内核结构的最大问题是性能问题,因为需要频繁地在核心态和用户态之间进行切换,操作系统的执行开销偏大。因此有的操作系统将那些频繁使用的系统服务又移回内核,从而保证系统性能。但是有相当多的实验数据表明,体系结构不是引起性能下降的主要因素,体系结构带来的性能提升足以弥补切换开销带来的缺陷。为减少切换开销,也有人提出将系统服务作为运行库链接到用户程序的一种解决方案,这样的体系结构称为库操作系统。
特点
- 模块化:微内核将操作系统的功能划分为不同的服务,每个服务运行在用户态,通过消息传递等方式实现模块间的通信,使得内核本身非常精简。
- 扩展性高:由于微内核的设计更加模块化,因此内核的扩展和修改相对容易,可以根据需要添加新的服务或者替换现有的服务。
- 性能开销大:由于模块间的通信和调度需要在用户态和内核态之间切换,因此微内核的性能通常比宏内核略低。
Linux 借鉴了微内核精髓的宏内核结构
经过上面这些描述之后,我们很容易把宏内核和微内核的特征想象成软件开发中的单体架构和微服务架构。单体架构最大的特点就是函数调用方便,不需要借助额外的通信机制。而微服务的架构之间的调用链路会比较长,可拓展性比较强。这两种不同的内核结构有不同的支持者,就和有些人认为单体架构好,有些人认为微服务架构模式好。
这就像对编程语言的争论一样,你说 Python 、Go、Java 以及其他语言哪个好?管他哪个好,最终都会戏谑的称 PHP 是这个世界上最好的语言。所以,这些争论本没有意义,但是很有趣的是,这种争论常常让人想起前几年在 CPU 领域中 RISC 和 CISC 之间的斗争。
现代成功的 CPU 设计包括这两种技术中的任何一种,就像 Linux 内核是微内核和宏内核的混合产品一样。可能有些人认为 Linux 它不就是个宏内核结构么,但实际上 Linux 不单单只是一个纯碎的集成内核。
Linux 是一个借鉴了微内核精髓的宏内核结构,Linux 支持模块化的设计、抢占式内核、对内核线程的支持以及动态加载内核模块的能力。不仅如此,Linux 还避免了其微内核设计的性能损失,允许一切运行在内核模式下,直接调用函数,无需消息传递。
所以综合一点来讲,Linux 是一个模块化、多线程和内核可调度的操作系统。
-
模块化的设计:Linux 支持内核模块的动态加载,尽管 Linux 内核也是单核,但它允许在需要时动态删除和加载一些内核代码。
-
可抢占性:Linux 内核支持可抢占
总结
宏内核和微内核各有其优劣势,适用于不同的应用场景和需求。宏内核适用于对性能要求较高、需求稳定的系统,而微内核适用于对灵活性和可维护性要求较高的系统。在实际应用中,选择合适的内核架构需要根据具体的系统需求、性能要求和可维护性等方面进行综合考量。