8

我是 C 程序员,是 Linux 内核编程的新手。我可以发现有 3 种类型的内核单片,微型和模块化内核。在谷歌搜索时,我可以找到一些网站说 linux 具有单片内核(在堆栈溢出中),而另一些则说微内核,其余的说混合内核。所以我在阅读模块化概念时完全感到困惑,它说可以在不重新编译内核的情况下添加驱动程序的新模块,这与我认为 Linux 使用单片内核的假设背道而驰。单片内核在单个地址空间中运行,并且作为单个进程 ,如果是这样的话,这也有点令人困惑

4

3 回答 3

11

在尝试理解这些差异之前,您必须先了解其他概念:

1.模块化编程。

模块是程序功能完整的部分。模块通常具有以下属性:

  1. 接口实现分离。
  2. 初始化去初始化例程。两者都是可选的。带有 GC(垃圾收集器)的环境中可能缺少去初始化例程。
  3. 程序使用的模块组成有向无环图,也称为依赖图(您可能听说过 - 不允许循环依赖,依赖在依赖模块之前初始化)。

在构建大型系统时,模块化编程是必不可少的。每个大内核都是模块化内核,无论是单体内核、混合内核还是微内核。

有时可以动态加载和卸载模块。动态模块是任何可扩展系统的重要组成部分。这些可以是插件,或者,如果我们谈论内核,则可以是与内核分开开发和分发的驱动程序。

2. 安全和不安全的语言。

安全语言非常严格地定义了程序中可能发生的事情。最重要的是,他们没有畸形程序(或无意义程序)的概念。每个程序都是有效的,它的执行总是遵循语言规范。在这种情况下,程序是否执行程序员期望它执行的操作是无关紧要的。

安全语言的共同特征:

  1. 他们使用垃圾收集。
  2. 他们没有指针算术。这意味着不允许写入或读取任意地址。
  3. 它们防止超出范围的数组访问(如果有这样的概念)。异常或类似机制可用于发出信号并从此类故障中恢复。
  4. 引用(或指针)只有两种可能的状态:空引用和对有效对象的引用。这是由垃圾收集器保证的。事实上,GC 是这里的关键组件。有些语言走得更远,根本不允许空引用。
  5. 每个对象(正在使用的内存块)都有分配给它的类型信息,对象只能通过适当类型的引用来访问,例如,您不能通过引用字符串来访问整数数组。

您可以在此列表中添加更多条目,但基本思想是保证程序只能使用有效操作访问有效内存区域。请记住,一些不安全的语言可以共享部分甚至全部这些特征。

安全语言示例:Python、Java、C# 的安全子集。

不安全的语言定义了程序中可以做什么和不可以做什么,但通常几乎没有什么可以阻止程序员做错事。违反这些规则的程序称为畸形程序。从语言的角度来看,这样的程序是没有意义的,语言甚至没有尝试定义它的行为,因为它通常几乎不可能做到。就 C 而言,此类程序的行为是undefined

不安全语言的示例:汇编程序、C、C++、Pascal。

3. 硬件不安全,因此必须使用不安全的语言进行编程。

大多数硬件无法为您提供安全的环境。有一些处理器用于将类型信息附加到每个内存单元(请参阅标记的架构),但现代处理器不会这样做,因为它会使硬件复杂化,使其速度更慢、更昂贵且通用性更低。

尽管如此,仍然提供了一些功能,以便在不安全的硬件环境中实现安全环境,例如内存保护、单独的地址空间以及用户模式内核模式(又名主管模式)上的执行模式分离。

内核是在裸机上运行的,因此其中大部分必须用 C 和汇编等不安全的语言编写。另一个原因是性能——安全的环境意味着巨大的开销。

微内核和单体内核

单片内核及其模块在单个共享地址空间中运行。而且由于所有内容通常都是用不安全的语言编写的,因此内核的任何部分都可能由于代码中的错误而访问(并损坏)属于内核另一部分的内存。这种环境的不安全性质使得无法检测到这些故障或从这些故障中恢复,最重要的是无法预测此类故障后的内核行为。

微内核试图通过将内核的各个部分移动到单独的地址空间来克服这些限制,有效地将它们彼此隔离,但提供彼此通信的安全方式(通常通过消息传递)。这种分离创建了由多个不安全进程组成的安全环境,允许内核从其某些子系统的故障中恢复。

同时,单片内核能够在单独的地址空间 ( FUSE ) 中运行它的一部分,而没有什么能阻止微内核能够支持与内核的主要部分共享地址空间的模块。

如果大部分内核运行在单个地址空间中,则认为它是一个单片内核。如果其中大部分运行在单独的地址空间中,则此类内核被认为是微内核。如果内核介于两者之间并积极使用这两种方法,那么您就有一个混合内核

混合内核

混合内核的概念意味着两全其美,是微软在 90 年代为促进 Windows NT 的销售而发明的。玩笑!但这几乎是真的。Windows NT 的每个重要部分都在共享地址空间中运行,因此它是单体设计的另一个例子。

在描述能够动态加载模块的单片内核时,许多人似乎使用这个术语。这是因为过去单片内核不支持动态模块加载,并且每次将模块添加到内核时都必须重新编译。微内核不是关于动态模块加载,而是关于内核的可靠性,关于它从子系统故障中恢复的能力。


答案:Linux 是一个单片内核。


单片内核可以是模块化的,并且可以动态加载模块。另一方面,微内核必须是模块化的,并且必须能够动态加载模块——整个想法是在单独的地址空间中运行它们。


微内核并不是克服单体内核不安全性质的唯一方法。另一种方法是用安全的语言编写单片内核。这种方法的一个问题是安全环境应该由硬件提供(并且将非常有限),或者应该使用不安全的语言在软件中实现。这种环境的实现将非常复杂,并且很可能会有很多错误(想想在 JVM 中发现的所有错误)。

这方面的例子是实验性 OS Singularity

于 2017-10-29T02:38:36.727 回答
0

有关您的问题的一些信息,请参阅此先前的 StackOverflow问题。简而言之,这听起来像你想知道......

...阅读模块化概念,即可以在不重新编译内核的情况下添加驱动程序的新模块,这与我认为 Linux 使用单片内核的假设背道而驰。单片内核在单个地址空间中运行并作为单个进程...

这两个概念(“模块化内核”和“单一地址空间”)实际上并不矛盾。您可以构建一个新的内核模块,而无需重新编译整个 Linux 内核。当您加载这个新的内核模块时,它实际上将被加载到与正在运行的内核本身相同的地址空间中。从上面的链接...

不要将术语模块化内核混淆为单片。一些单片内核可以编译成模块化的(例如Linux),重要的是模块插入到处理核心功能的同一空间(内核空间)并从其运行。

正如您所发现的,有几种方法可以对内核进行分类,并且不同的类型不一定是相互排斥的。

于 2017-11-02T17:50:27.353 回答
0

好吧,考虑到我明天可能会有一个关于这个的测验,我应该能够帮助你。但是,我还在学习中,虽然我的帖子可能存在一些技术错误,但在概念上应该是合理的

基本上,正如您可能理解的那样,操作系统有不同类型的内核。

单片内核将所有系统功能和服务集中在一个巨大的程序中,占用一个地址空间。另一方面,微内核在微内核上拥有最少的系统程序和服务。大多数以前被认为是内核的一部分(在单片内核版本期间)的服务,例如进程调度程序等,现在都在用户空间中,被称为服务器。这些服务器通过微内核相互通信,使用进程间通信,一种由微内核制定的通信形式。模块化方法以此为基础,通过使这些“服务器”动态加载。因此,可以动态加载特定的“服务器”(在这种类型的内核中,称为模块),

Linux Kernel 是一个单片内核,但大多数Linux 风格,如Ubuntu、Solaris,都使用混合内核,即混合了单片内核和模块化内核方法。这很常见,不同的内核结构有不同的优缺点,需要混合结构来平衡

于 2017-09-27T06:29:56.903 回答