微内核与宏内核比较
内核按照体系结构分为两类:微内核(microkernel)与宏内核(macrokernel). 微内核的系统有WindowNT,Minix,Mach,etc.宏内核的系统有Unix,Linux,etc.通过比较Minix和Linux来比较微内核和宏内核是很有意思的,因为当年两个系统的创始人对两种内核的优劣有过争论.
两个系统的内核是通过进程的创建FORK的实现来比较,因为进程的创建涉及到系统调用,内存管理,文件管理等系统的主要方面.因此通过比较FORK的实现可以大致看到内核的差别.
微内核的代表:Minix
在Minix中,操作系统的内核,内存管理,系统管理都有自己的进程表,每个部分的表包含了自己需要的域。表象是精确对应的,为了保持同步,在进程创建或结束时,这三个部分都要更新各自的表。
由内存管理器协调。
系统启动后,kernel,mm,fs系统进程在各自的空间运行main()函数循环等待消息
While(TRUE)
{…
receive(ANY,&mm_in);
…}
当一个FORK传给mm’main(),main()调用do_fork(),do_fork()函数把父进程的data segment和stack segment创造了一个精确副本给子进程,并把父进程的text segment 与子进程共享,然后在mm的进程表mproc[]中添加新进程,并设置各属性。添加完后发送消息给kernel(sys_fork(…))和 fs(tell_fs(…)).,kernel中的函数sys_task()接收到系统信息,调用do_fork(message * m_ptr),copy parent’proc struct to child.并设置进程在内核进程表中的属性。tell_fs()是内存管理器与文件系统之间的接口,tell_fs(…)调用 _taskcall(…),文件管理器接收到FORK系统消息,调用do_fork()函数,copy parent’fproc struct to child.并设置进程在文件进程表中的属性。这样整个进程的属性就设置完成.
在Minix创建新进程的过程中,可以看到一个很大特点,就是整个系统按功能分成几个部分,各模块之间利用消息机制通信,调用其他模块的函数必须通过目标模块的守护进程调用.
宏内核的代表:Linux
在Linux中,进程的结构如下:
Struct task_struct{
pid_t pid;
pid_t pgrp;
…
/* filesystem information */
struct fs_struct *fs;
/* memory management info*/
struct mm_struct *mm;
…
};
在Linux进程的结构定义中,task_struct包含了所有的信息,包括进程的内存情况,文件系统情况。在创建新进程时,系统调用sys_fork调用do_fork(…)函数.
int do_fork(unsigned long clong_flags,… )
{
struct task_struct *p;
p->pid = get_pid(clone_flags);
…
/* copy all the process information*/
copy_files(clone_flags,p);
copy_fs(clone_flags,p);
copy_mm(nr,clone_flags,p);
…
}
在创建进程时,do_fork函数把所有的工作完成,分配pid…号,拷贝父进程数据段,堆栈段,等等。Linux的进程创建过程是一个完整的过程,直接调用其他模块的函数,而不是消息传递。
Minix与Linux创建新进程的过程比较可以看出二者之间的区别,Minix是建立在分模块之上的,模块之间以信息传递联系。Linux内部也是分模块的,但在运行的时候,他是一个独立的二进制大映像,其模块间的通讯是通过直接调用其他模块中的函数实现的。宏内核与微内核的区别也就在这吧,微内核是一个信息中转站,自身完成很少功能,主要是传递一个模块对另一个模块的功能请求,而宏内核则是一个大主管,把内存管理,文件管理等等一股脑全部接管。
从理论上来看,微内核的思想更好些,微内核把系统分为各个小的功能块,降低了设计难度,系统的维护与修改也容易,但通信带来的效率损失是个问题。宏内核的功能块之间的耦合度太高造成修改与维护的代价太高,不过在目前的Linux里面还不算大问题,因为Linux目前还不算太复杂,宏内核因为是直接调用,所以效率是比较高的。
=================================================
这两种派系的代表人分别是Tanenbaum和Linus。 Tanenbaum的一段话比较通俗易懂的说明了什么叫微内核什么叫宏内核。 “老一点的操作系统都是宏内核的,也就是说,整个操作系统是一个运行在核心态的单独的a.out文件, 这个二进制文件包含进程管理,内存管理,文件系统以及其他。具体实例包括UNIX,MS-DOS,VMS,MVS, OS/360,MULTICS等等。 另一种便是微内核,在这种系统中,操作系统的大部分都运行在单独的进程,而且多数在内核之外。它们 之间通过消息传递来通信。内核的任务是处理消息传递,中断处理,底层的进程管理,以及可能的I/O。 这种设计实例有RC4000,Amoeba,Chorus,Mach以及还没有发布的Windows/NT”。
为了从概念上搞清楚微内核和宏内核,从网上搜到如下的资料
“l 微内核(Microkernel kernel)――在微内核中,大部分内核都作为独立的进程在特权状态下运行,它们通过消息传递进行通讯。在典型情况下,每个概念模块都有一个进程。因此,如果在设计中有一个系统调用模块,那么就必然有一个相应的进程来接收系统调用,并和能够执行系统调用的其它进程(或模块)通讯以完成所需任务。
在这些设计中,微内核部分经常只不过是一个消息转发站:当系统调用模块要给文件系统模块发送消息时,消息直接通过内核转发。这种方式有助于实现模块间的隔离。(某些时候,模块也可以直接给其它模块传递消息。)在一些微内核的设计中,更多的功能,如I/O等,也都被封装在内核中了。但是最根本的思想还是要保持微内核尽量小,这样只需要把微内核本身进行移植就可以完成将整个内核移植到新的平台上。其它模块都只依赖于微内核或其它模块,并不直接直接依赖硬件。
微内核设计的一个优点是在不影响系统其它部分的情况下,用更高效的实现代替现有文件系统模块的工作将会更加容易。我们甚至可以在系统运行时将开发出的新系统模块或者需要替换现有模块的模块直接而且迅速的加入系统。另外一个优点是不需要的模块将不会被加载到内存中,因此微内核就可以更有效的利用内存。
l 单内核(Monolithic kernel)――单内核是一个很大的进程。它的内部又可以被分为若干模块(或者是层次或其它)。但是在运行的时候,它是一个独立的二进制大映象。其模块间的通讯是通过直接调用其它模块中的函数实现的,而不是消息传递。
单内核的支持者声称微内核的消息传递开销引起了效率的损失。微内核的支持者则认为因此而增加的内核设计的灵活性和可维护性可以弥补任何损失
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/elephantear/archive/2005/05/27/382576.aspx
=====================================================
微内核和宏内核各自的工作原理我想读者已经明白了。同时它们的优缺点也基本上清楚了。宏内核的优势在于其逻辑简单,直截了当,实现起来也容易,而且也因为它的直接,避免了像微内核那样在消息传递时占用资源。而微内核的优势在于,它的逻辑虽相对复杂但非常严谨,结构上显得非常优雅和精致,而且程序更容易模块化,从而更容易移植。
从编程的难易程度上来看,宏内核看上去具有一定优势,因为它很直接,不需要绕弯子,但从长期来看,当内核逐渐变大,微内核的结构会更加清晰。虽然选择微内核意味着有调试起来有些困难的消息机制摆在面前,但从设计理念上来看,微内核更加“摩登”,更“酷”。而且,从学习编程的角度看,搞一个微内核可以为将来架构其他东西作为很有益的参考。基于这些原因,我们选择微内核。
微内核和宏内核
今天看了《程序员》上的一篇文章,对微内核和宏内核,在系统调用的角度上,有了比较清晰地认识。 这两种派系的代表人分别是Tanenbaum和Linus。 Tanenbaum的一段话比较通俗易懂的说明了什么叫微内核什么叫宏内核。 “老一点的操作系统都是宏内核的,也就是说,整个操作系统是一个运行在核心态的单独的a.out文件, 这个二进制文件包含进程管理,内存管理,文件系统以及其他。具体实例包括UNIX,MS-DOS,VMS,MVS, OS/360,MULTICS等等。 另一种便是微内核,在这种系统中,操作系统的大部分都运行在单独的进程,而且多数在内核之外。它们 之间通过消息传递来通信。内核的任务是处理消息传递,中断处理,底层的进程管理,以及可能的I/O。 这种设计实例有RC4000,Amoeba,Chorus,Mach以及还没有发布的Windows/NT”。
为了从概念上搞清楚微内核和宏内核,从网上搜到如下的资料
“l 微内核(Microkernel kernel)――在微内核中,大部分内核都作为独立的进程在特权状态下运行,它们通过消息传递进行通讯。在典型情况下,每个概念模块都有一个进程。因此,如果在设计中有一个系统调用模块,那么就必然有一个相应的进程来接收系统调用,并和能够执行系统调用的其它进程(或模块)通讯以完成所需任务。
在这些设计中,微内核部分经常只不过是一个消息转发站:当系统调用模块要给文件系统模块发送消息时,消息直接通过内核转发。这种方式有助于实现模块间的隔离。(某些时候,模块也可以直接给其它模块传递消息。)在一些微内核的设计中,更多的功能,如I/O等,也都被封装在内核中了。但是最根本的思想还是要保持微内核尽量小,这样只需要把微内核本身进行移植就可以完成将整个内核移植到新的平台上。其它模块都只依赖于微内核或其它模块,并不直接直接依赖硬件。
微内核设计的一个优点是在不影响系统其它部分的情况下,用更高效的实现代替现有文件系统模块的工作将会更加容易。我们甚至可以在系统运行时将开发出的新系统模块或者需要替换现有模块的模块直接而且迅速的加入系统。另外一个优点是不需要的模块将不会被加载到内存中,因此微内核就可以更有效的利用内存。
l 单内核(Monolithic kernel)――单内核是一个很大的进程。它的内部又可以被分为若干模块(或者是层次或其它)。但是在运行的时候,它是一个独立的二进制大映象。其模块间的通讯是通过直接调用其它模块中的函数实现的,而不是消息传递。
单内核的支持者声称微内核的消息传递开销引起了效率的损失。微内核的支持者则认为因此而增加的内核设计的灵活性和可维护性可以弥补任何损失。l 微内核(Microkernel kernel)――在微内核中,大部分内核都作为独立的进程在特权状态下运行,它们通过消息传递进行通讯。在典型情况下,每个概念模块都有一个进程。因此,如果在设计中有一个系统调用模块,那么就必然有一个相应的进程来接收系统调用,并和能够执行系统调用的其它进程(或模块)通讯以完成所需任务。
在这些设计中,微内核部分经常只不过是一个消息转发站:当系统调用模块要给文件系统模块发送消息时,消息直接通过内核转发。这种方式有助于实现模块间的隔离。(某些时候,模块也可以直接给其它模块传递消息。)在一些微内核的设计中,更多的功能,如I/O等,也都被封装在内核中了。但是最根本的思想还是要保持微内核尽量小,这样只需要把微内核本身进行移植就可以完成将整个内核移植到新的平台上。其它模块都只依赖于微内核或其它模块,并不直接直接依赖硬件。
微内核设计的一个优点是在不影响系统其它部分的情况下,用更高效的实现代替现有文件系统模块的工作将会更加容易。我们甚至可以在系统运行时将开发出的新系统模块或者需要替换现有模块的模块直接而且迅速的加入系统。另外一个优点是不需要的模块将不会被加载到内存中,因此微内核就可以更有效的利用内存。
l 单内核(Monolithic kernel)――单内核是一个很大的进程。它的内部又可以被分为若干模块(或者是层次或其它)。但是在运行的时候,它是一个独立的二进制大映象。其模块间的通讯是通过直接调用其它模块中的函数实现的,而不是消息传递。
单内核的支持者声称微内核的消息传递开销引起了效率的损失。微内核的支持者则认为因此而增加的内核设计的灵活性和可维护性可以弥补任何损失。”
在了解这些知识的基础上,再看到杂志上的图解,就变得非常清楚了。
操作系统内核可能是微内核,也可能是单内核(后者有时称之为宏内核Macrokernel)。按照类似封装的形式,这些术语定义如下:
l
微内核(Microkernel
kernel)――在微内核中,大部分内核都作为独立的进程在特权状态下运行,它们通过消息传递进行通讯。在典型情况下,每个概念模块都有一个进程。因此,如果在设计中有一个系统调用模块,那么就必然有一个相应的进程来接收系统调用,并和能够执行系统调用的其它进程(或模块)通讯以完成所需任务。
在这些设计中,微内核部分经常只不过是一个消息转发站:当系统调用模块要给文件系统模块发送消息时,消息直接通过内核转发。这种方式有助于实现模块间的隔离。(某些时候,模块也可以直接给其它模块传递消息。)在一些微内核的设计中,更多的功能,如I/O等,也都被封装在内核中了。但是最根本的思想还是要保持微内核尽量小,这样只需要把微内核本身进行移植就可以完成将整个内核移植到新的平台上。其它模块都只依赖于微内核或其它模块,并不直接直接依赖硬件。
微内核设计的一个优点是在不影响系统其它部分的情况下,用更高效的实现代替现有文件系统模块的工作将会更加容易。我们甚至可以在系统运行时将开发出的新系统模块或者需要替换现有模块的模块直接而且迅速的加入系统。另外一个优点是不需要的模块将不会被加载到内存中,因此微内核就可以更有效的利用内存。
l 单内核(Monolithic
kernel)――单内核是一个很大的进程。它的内部又可以被分为若干模块(或者是层次或其它)。但是在运行的时候,它是一个独立的二进制大映象。其模块间的通讯是通过直接调用其它模块中的函数实现的,而不是消息传递。
单内核的支持者声称微内核的消息传递开销引起了效率的损失。微内核的支持者则认为因此而增加的内核设计的灵活性和可维护性可以弥补任何损失。
我并不想讨论这些问题,但必须说明非常有趣的一点是,这种争论经常会令人想到前几年CPU领域中RISC和CISC的斗争。现代的成功CPU设计中包含了所有这两种技术,就像Linux内核是微内核和单一内核的混合产物一样。Linux内核基本上是单一的,但是它并不是一个纯粹的集成内核。前面一章所介绍的内核模块系统将微内核的许多优点引入到Linux的单内核设计中。(顺便提一下,我考虑过一种有趣的情况,就是Linux的内核模块系统可以将系统内核转化成为简单的不传递消息的微内核设计。虽然我并不赞成,但是它仍然是一个有趣的想法。)
为什么Linux必然是单内核的呢?一个方面是历史的原因:在Linus的观点看来,通过把内核以单一的方式进行组织并在最初始的空间中运行是相当容易的事情。这种决策避免了有关消息传递体系结构,计算模块装载方式等方面的相关工作。(内核模块系统在随后的几年中又进行了不断地改进。)
另外一个原因是充足的开发时间的结果。Linux既没有开发时间的限制,也没有深受市场压力的发行进度。所有的限制只有并不过分的对内核的修改与扩充。内核的单一设计在内部实现了充分的模块化,在这种条件下的修改或增加都并不怎么困难。而且问题还在于没有必要为了追求尚未证实的可维护性的微小增长而重写Linux的内核。(Linus曾多次特别强调了如下的观点:为了这点利益而损耗速度是不值得的。)后面章节中的部分内容将详细的重新考虑充足开发时间的效果。
如果Linux是纯微内核设计,那么向其它体系结构上的移植将会比较容易。实际上,有一些微内核,如Mach微内核,就已经成功的证明了这种可移植性的优点。实际的情况是,Linux内核的移植虽然不是很简单,但也绝不是不可能的:大约的数字是,向一个全新的体系结构上的典型的移植工作需要
30,000到60,000行代码,再加上不到20,000行的驱动程序代码。(并不是所有的移植都需要新的驱动程序代码。)粗略的计算一下,我估计一个典型的移植平均需要50,000行代码。这对于一个程序员或者最多一个程序小组来说是力所能及的,可以在一年之内完成。虽然这比微内核的移植需要更多的代码,但是Linux的支持者将会提出,这样的Linux内核移植版本比微内核更能够有效的利用底层硬件,因而移植过程中的额外工作是能够从系统性能的提高上得到补偿的。
这种特殊设计的权衡也不是很轻松就可以达到的,单内核的实现策略公然违背了传统的看法,后者认为微内核是未来发展的趋势。但是由于单一模式(大部分情况下)在Linux中运行状态良好,而且内核移植相对来说比较困难,但没有明显地阻碍程序员团体的工作,他们已经热情高涨地把内核成功的移植到了现存的大部分实际系统中,更不用说类似掌上型电脑的一些看起来很不实际的目标了。只要Linux的众多特点仍然值得移植,新的移植版本就会不断涌现。