在尝试理解这些差异之前,您必须先了解其他概念:
1。模块化编程。
模块是程序功能完整的部分。模块通常具有以下属性:
- 分离接口和实现。
-
初始化和去初始化例程。两者都是可选的。带有 GC(垃圾收集器)的环境中可能缺少取消初始化例程。
- 程序使用的模块组成有向无环图,也称为依赖图(您可能听说过 - 不允许循环依赖,依赖在依赖模块之前初始化)。
在构建大型系统时,模块化编程是必不可少的。每个大内核都是一个模块化内核,无论它是单体内核、混合内核还是微内核。
有时模块可以动态加载和卸载。动态模块是任何可扩展系统的重要组成部分。这些可以是插件,或者,如果我们谈论内核,则可以是独立于内核开发和分发的驱动程序。
2。安全和不安全的语言。
安全语言非常严格地定义程序中可能发生的事情。最重要的是,他们没有malformed 程序(或无意义 程序)的概念。每个程序都是有效的,它的执行总是遵循语言规范。程序是否按照程序员期望的那样做,在这种情况下是无关紧要的。
安全语言的共同特征:
- 他们使用垃圾收集。
- 它们没有指针算法。这意味着不允许写入或读取任意地址。
- 它们防止超出范围的数组访问(如果有这样的概念)。异常或类似机制可用于发出信号并从此类故障中恢复。
- 引用(或指针)只有两种可能的状态:空引用和对有效对象的引用。这是由垃圾收集器保证的。事实上,GC 是这里的关键组件。有些语言走得更远,根本不允许空引用。
- 每个对象(正在使用的内存块)都有分配给它的类型信息,对象只能通过适当类型的引用来访问,例如您不能通过引用字符串来访问整数数组。
您可以在此列表中添加更多条目,但基本思想是保证程序只能使用有效操作访问有效内存区域。请记住,一些不安全的语言可能会共享部分甚至全部这些特征。
安全语言示例:Python、Java、C# 的安全子集。
不安全的语言定义了程序中可以做什么和不可以做什么,但通常没有什么可以阻止程序员做错事。违反这些规则的程序称为格式错误的程序。从语言的角度来看,这样的程序是没有意义的,语言甚至没有尝试定义它的行为,因为它通常几乎不可能做到。就 C 而言,此类程序的行为是 undefined。
不安全语言的示例:汇编程序、C、C++、Pascal。
3。硬件不安全,因此必须使用不安全的语言进行编程。
大多数硬件无法为您提供安全的环境。有一些处理器用于将类型信息附加到每个内存单元(请参阅 tagged architecture),但现代处理器不会这样做,因为它会使硬件复杂化,使其速度更慢、更昂贵且通用性更低。
仍然提供了一些功能,以便在不安全的硬件环境中实现安全环境,例如内存保护、单独的地址空间以及 用户模式和 上的执行模式分离内核模式(又名主管模式)。
内核是在裸机上运行的,因此其中大部分必须用 C 和汇编等不安全的语言编写。另一个原因是性能 - 安全的环境意味着巨大的开销。
微内核和单体内核
单片内核及其模块在单个共享地址空间中运行。而且由于所有内容通常都是用不安全的语言编写的,因此内核的任何部分都可能由于代码中的错误而访问(并损坏)属于内核另一部分的内存。这种环境的不安全性质使得无法检测到这些故障或从这些故障中恢复,最重要的是无法预测此类故障后的内核行为。
微内核试图通过将内核的各个部分移动到单独的地址空间来克服这些限制,有效地将它们彼此隔离,但提供相互通信的安全方式(通常通过消息传递)。这种分离创建了由多个不安全进程组成的安全环境,允许内核从其某些子系统的故障中恢复。
同时,单片内核可以在单独的地址空间 (FUSE) 中运行它的一部分,而没有什么能阻止微内核能够支持与内核的主要部分共享地址空间的模块。
如果大部分内核运行在一个单一的地址空间,它被认为是一个单片内核。如果其中大部分运行在单独的地址空间中,则此类内核被认为是微内核。如果内核介于两者之间并积极使用这两种方法,那么您就有了一个混合内核。
混合内核
混合内核的概念意味着将两全其美的结合在一起,由微软在 90 年代为促进 Windows NT 的销售而发明。玩笑!但这几乎是真的。 Windows NT 的每个重要部分都在共享地址空间中运行,因此它是单体设计的另一个例子。
在描述能够动态加载模块的单片内核时,许多人似乎都使用了这个术语。这是因为过去单片内核不支持动态模块加载,并且每次将模块添加到内核时都必须重新编译。微内核不是关于动态模块加载,而是关于内核的可靠性,关于它从子系统故障中恢复的能力。
答案:Linux 是一个单体内核。
单片内核可以是模块化的并且可以动态加载模块。另一方面,微内核必须是模块化的,必须能够动态加载模块——整个想法是在单独的地址空间中运行它们。 p>
微内核并不是克服单体内核不安全特性的唯一方法。另一种方法是用安全的语言编写单片内核。这种方法的一个问题是安全环境应该由硬件提供(并且将非常有限),或者应该使用不安全的语言在软件中实现。这种环境的实现将非常复杂,并且很可能会有很多错误(想想在 JVM 中发现的所有错误)。
这方面的示例是实验性操作系统Singularity。