為什麼 Linux 不用微內核?

明明微內核有好處,都不選用?


有關單內核和微內核之爭由來已久,Tanenbaum在1992年就此事同Linus展開了一場論述,這場論述可以說截止到今天也沒有誰能說服誰,具體內容可以看這裡

http://en.wikipedia.org/wiki/Tanenbaum%E2%80%93Torvalds_debate

在Tanenbaum的說法中,Linux單內核的設計主要存在幾個問題:

  1. Linux設計之初的單內核思想使得它同80x86的處理器架構緊緊綁定在了一起,這導致Linux的移植性低於Minix。
  2. 代碼的錯誤取決於代碼大小。一般而言工業代碼每千行會出現10個錯誤。將越多的代碼放到內核,內核的出錯可能性也越大。
  3. 操作系統的設計不應該因為某些代碼中偶然出現的錯誤影響到整個內核的運行。

而基於Tanebaum的質疑,Linus也給出了自己的回答。他承認在理論和美學方面上,微內核是領先於單內核的,而他也承認Minix的移植性從某些方面是要好於Linux。但他解釋說Linux的Intel x86架構的綁定是因為Linux只不過源於他的操作系統實驗而已。但是由於他簡化了Linux的API介面,並且使其更具有移植性,事實上 「linux is more portable than minix.」。

事實上,正是由於單內核和微內核各有優缺點,這場爭論一直持續到現在。單內核和微內核在當前各有其應用,例如,微內核的windows,symbian,教學專用的Minix,單內核的Linux等。

在效率上而言,單內核是要超過微內核的。可以想像一下,在windows桌面移動一下滑鼠就要發送幾十條消息,就要陷入到內核之中多次。操作系統的管態用戶態轉變是代價很高的,這個對操作系統有一點點常識的人都能知道。而Linux則不需要,因為大部分內核代碼都在內核態執行,不需要通過消息傳遞的方式通訊,也不需要大量的用戶態內核態轉化開銷,因此效率要高很多。

至於在代碼錯誤影響方面,微內核的錯誤容忍度一般是要好於單內核的。微內核可以將大部分的設備驅動包括文件系統都放入到用戶空間中,內核中只運行很小一部分代碼,例如Minix只有3200行的C代碼和800行的底層代碼在內核中。用戶空間中的模塊出現的錯誤會導致模塊崩潰,但不會導致內核故障。而單內核架構內核代碼龐大,一旦其中出現任何故障,可能會直接導致內核崩潰。

我自己也寫過微內核的小型操作系統,包括簡單的shell等等。消息處理是微內核比較重要的模塊,編寫代碼的過程中保證消息傳遞的成功,我就覺得已經成功了50%。而Linux的單內核架構編寫就需要注意很多問題,各種控制資源競爭的自旋鎖讓人會讓痛不欲生的。

總而言之,Linux使用單內核並不說明單內核好於微內核。而微內核在某些方面強於單內核也並不說明Linux就應該使用微內核。

b.t.w : Linus最後也給Tanenbaum發過郵件為這場爭論做了Apologize。畢竟Linus是看了Tanenbaum的操作系統教程和Minix源碼才學寫的Linux。而Tanenbaum的X86很快會過時,Linux很快會淘汰的語言也被時間證明是錯誤的。或許有一天Linux也會被微內核的更新的操作系統所替代了呢~


Tanenbaum同學的一個基本論點是,代碼的bug數量和代碼的長度成正比關係。所以他費勁心思要縮短內核空間的代碼量,把儘可能多的東西移到用戶空間去。

而Linus同學肯定不相信這種鬼話,有次他在Google Tech Talk講git時就大言不慚說,「每個人的代碼都不是第一次就正確,除了我」


有好處就肯定有壞處。

微內核的壞處,光性能損耗一條就夠了。那麼多驅動運行在非0態,每次進程調度導致 TLB 刷新,調度後運行稍微多些代碼,又導致L1、L2 失效。

我也很喜歡微內核,但是還是覺得現在通用的體系結構無法高效使用,期待新的架構體系能為我們提供又穩定,性能又高的微內核系統。


GNU/HURD就是微內核的呀,你如果感興趣,可以使用kexec命令自動切換內核去嘗試一下(不需要重啟哦~)


理解為什麼要內核?

內核,目的是為了防止有bug的代碼,破壞別的正常的代碼,甚至破壞硬體。

如果代碼都是經過嚴格測試的,那麼可以不需要分內核空間來保護。

於是只要我們能夠保證我們加入內核的代碼足夠健壯,那麼內核可以十分巨大,甚至於不使用內核

優缺點。

如其他人所說,內核的缺點,切換起來消耗時間。所以宏內核講究把更多的內容經過設計和測試之後,放入內核,這樣更高執行效率。微內核講究,內核中只有幾千行代碼,這樣能夠更好的設計和測試,測試人力上簡單。

二者是效率與設計測試工作量的權衡。

Linux如何選擇?

Linux屬於工程派,不刻意選擇哪種內核,而是在穩定性可以得到保證的情況下,盡量選擇更快的方式,不追求學院派的美觀。

也許,當年Linux工程師們發現,就那麼一點driver,又不會出錯,為了美觀而犧牲效率完全不值得。

再或者,如果有一種神奇的方法,能夠把X windows代碼測試的十分穩定,那麼把X windows加入內核也不錯。似乎以前windows就是GUI測試的很好,然後放入了內核。

例如,當Linux工程師們發現driver的code太多了,而且太亂,又不捨得將driver全部踢出內核,於是開始使用module來載入驅動。

再例如,SoC興起之後,又發現driver的code再一次太多了,難以保證質量,還是捨不得把driver踢出內核,又做了device tree等機制。

如果有一天大家發現維護不過來了,然後把某些內容踢出內核,或者新的計算機架構下微內核又快又穩定,那麼Linux發展成為微內核也未嘗不可,難道Linux有一天不選擇宏內核,就不叫Linux了?


《Linux Kernel Development(Thied Edition)》1.4節說過這個問題,截圖奉上

對應的英文版:

Because the IPC mechanism involves quite a bit more overhead than a trivial function call,

however, and because a context switch from kernel-space to user-space or vice versa is

often involved, message passing includes a latency and throughput hit not seen on monolithic

kernels with simple function invocation. Consequently, all practical microkernel-based

systems now place most or all the servers in kernel-space, to remove the overhead of frequent

context switches and potentially enable direct function invocation. The Windows NT

kernel (on which Windows XP, Vista, and 7 are based) and Mach (on which part of Mac OS X

is based) are examples of microkernels. Neither Windows NT nor Mac OS X run any microkernel

servers in user-space in their latest iteration, defeating the primary purpose of microkernel

design altogether.

Linux is a monolithic kernel; that is, the Linux kernel executes in a single address space

entirely in kernel mode. Linux, however, borrows much of the good from microkernels: Linux

boasts a modular design, the capability to preempt itself (called kernel preemption), support

for kernel threads, and the capability to dynamically load separate binaries (kernel modules)

into the kernel image. Conversely, Linux has none of the performance-sapping features that

curse microkernel design: Everything runs in kernel mode, with direct function invocation—

not message passing—the modus of communication. Nonetheless, Linux is modular,

threaded, and the kernel itself is schedulable. Pragmatism wins again.

總結起來:1.現有的微內核系統,其實並不是真正意義上的微內核,部分實現違背了微內核的初衷

2.Linux並非拋棄不用微內核,而是吸取了其中部分優點,比如模塊化、搶佔、內核線程 等特點。

所以,為什麼不用微內核?

因為,實用主義佔上風!


主要是從運行效率方面考慮,一個單內核系統運行內部是一個大程序,主要依靠函數調用;微內核系統運行時,把文件系統,網路協議棧,大部分的進程管理功能作為服務進程在內核之外運行,這必然意味著大量的進程間通信;進程間通信和函數調用效率自然差得很遠。但是,也應該注意到,Linux kernel儘管是單內核的形式,但並不意味著它完全無視了微內核的設計思想,模塊機制就是微內核設計思想在Linux kernel中的體現。


宏內核實現上更簡單。PS:現代微內核(win、osx)中服務都運行在系統態,根本沒有「多次陷入內核」,驅動、文件系統bug都會導致系統崩潰,比如win藍屏。微內核更多指消息機制,提供基本的調用介面;而宏內核Linux一個模塊export_symbol後,其他模塊就能調用。類比RISC,CISC。實際上先進思想都相互融合了,已經沒有上述傳統的區分。例如,Linux編譯後內核本身能小於8MB(跟win內核kern大小接近),大部分作為模塊。再如,Linux的FUSE、User space driver等,豈不是傳統微內核中的概念。


這個主要是歷史問題,linux初始設計時就沒考慮微內核,後來經過20年的發展證明性能相當

不錯,為啥子還非要去轉型呢,而且這種轉型也是根本不可能的。微內核理論上是比較不錯

的,只是在初期一直沒有性能拿得出手的作品,比如gnu的hurd就一直在搞一直沒名堂,但是

有個IBM的德國員工搞了一個L3,後來發展出L4,現在ARM的准虛擬上被認為可圈可點。


因為他覺得

1. 單內核效率高

2. 他很屌,不會犯錯


推薦閱讀:

在做完內核裁剪後,等待編譯結果的過程是一種怎樣的體驗?
你為什麼學習 Linux 內核?
多個socket同時發送數據,網卡是輪流發送每個socket數據包嗎?每個包多大?

TAG:Linux | Linux內核 | 操作系統內核 |