操作系統(tǒng)是如何實(shí)現(xiàn)的:宏內(nèi)核 VS 微內(nèi)核
大家好,我是島主小風(fēng)哥,今天來聊聊操作系統(tǒng)兩種實(shí)現(xiàn)方式。
操作系統(tǒng)和普通的大型應(yīng)用程序項(xiàng)目類似,都涉及代碼組織方式的問題,但操作系統(tǒng)的獨(dú)特之處在于其核心部分必須運(yùn)行在內(nèi)核態(tài),kernel model,所謂內(nèi)核態(tài)嚴(yán)格講是指在該狀態(tài)下程序擁有對(duì)硬件(hardware)的所有控制權(quán),運(yùn)行在用戶態(tài)的程序做不到這一點(diǎn)。
有的同學(xué)可能會(huì)有疑問,操作系統(tǒng)(或者說內(nèi)核)不都是核心部分嗎?嚴(yán)格來講像進(jìn)程管理調(diào)度、內(nèi)存管理等就是核心部分,但像驅(qū)動(dòng)等就不是那么核心了,那么這一部分也需要放在內(nèi)核態(tài)嗎?
圍繞這一劃分,出現(xiàn)了兩種操作系統(tǒng)的設(shè)計(jì)方式,關(guān)于這兩種設(shè)計(jì)方法的爭(zhēng)論就和復(fù)雜指令集(CISC)與精簡(jiǎn)指令集(RISC)哪個(gè)更好一樣至今沒有非常明確的定論。
圖片
大一統(tǒng),全部運(yùn)行在內(nèi)核態(tài)
最簡(jiǎn)單的劃分就是沒有劃分,我們可以把所有內(nèi)核代碼放在內(nèi)核態(tài),內(nèi)核中的任何代碼都擁有控制硬件的全部特權(quán),顯然這種設(shè)計(jì)方法非常簡(jiǎn)單,因?yàn)椴僮飨到y(tǒng)設(shè)計(jì)者不用費(fèi)心去想哪一部分該放在內(nèi)核態(tài)。
由于全部?jī)?nèi)核程序都運(yùn)行在內(nèi)核態(tài),編譯好的內(nèi)核程序就是一個(gè)單獨(dú)的二進(jìn)制可執(zhí)行文件,這時(shí)的操作系統(tǒng)運(yùn)行起來后就是一個(gè)大進(jìn)程,所有內(nèi)核代碼運(yùn)行在一個(gè)單獨(dú)的地址空間中,這和我們實(shí)現(xiàn)的稍微復(fù)雜的單進(jìn)程應(yīng)用程序類似,這種大一統(tǒng)的設(shè)計(jì)就是所謂的宏內(nèi)核,monolithic kernel,個(gè)人認(rèn)為叫“一體化內(nèi)核”更形象些。
圖片
這種組織方式和TCP/IP協(xié)議棧的分層實(shí)現(xiàn)有點(diǎn)類似。
現(xiàn)在內(nèi)核代碼已經(jīng)組織好了,畢竟內(nèi)核是為上層應(yīng)用提供服務(wù)的,那么上層應(yīng)用該怎樣調(diào)用內(nèi)核代碼呢?這就是系統(tǒng)調(diào)用的作用,system call。
圖片
上層應(yīng)用程序通過系統(tǒng)調(diào)用與內(nèi)核進(jìn)行交互。
由于內(nèi)核代碼唯一同一個(gè)地址空間中,因此內(nèi)核中各部分的交互極為簡(jiǎn)單,就是普通的函數(shù)調(diào)用,文件系統(tǒng)中的某塊cache可以非常容易的被虛擬內(nèi)存系統(tǒng)共享使用。
但宏內(nèi)核也是有缺點(diǎn)的,由于內(nèi)核代碼位于同一個(gè)地址空間,代碼趨于復(fù)雜化,復(fù)雜就容易出錯(cuò),但內(nèi)核和普通程序不同,一旦內(nèi)核中某一模塊出現(xiàn)bug將導(dǎo)致整個(gè)內(nèi)核崩潰,底層的內(nèi)核崩潰后上層的應(yīng)用程序就無法繼續(xù)正常推進(jìn),整個(gè)系統(tǒng)就下圖一樣。。crash
當(dāng)然也有人不在乎在這一點(diǎn),Linus認(rèn)為內(nèi)核中有bug正常,有bug就找到它、修復(fù)它而不是用某種機(jī)制試圖忽略它,沒錯(cuò),C++中的異常就是試圖忽略bug的機(jī)制,這就是為什么很多公司的規(guī)范中禁止使用異常的原因。
總之,內(nèi)核崩潰后就必須重啟計(jì)算機(jī)。
保留核心,非必要不留在內(nèi)核
為減少內(nèi)核崩潰的風(fēng)險(xiǎn),一個(gè)簡(jiǎn)單的辦法就是讓內(nèi)核盡量精簡(jiǎn),只保留核心部分運(yùn)行在內(nèi)核態(tài),其它代碼以用戶態(tài)進(jìn)程的形式運(yùn)行,就像這樣:
圖片
運(yùn)行在用戶態(tài)的操作系統(tǒng)程序被稱為server,像負(fù)責(zé)文件操作的File Server等,此時(shí)用戶進(jìn)程想要使用操作系統(tǒng)提供的服務(wù)的話就必須借助進(jìn)程間通信,inter-process communication,即IPC,借助內(nèi)核,消息從一個(gè)進(jìn)程發(fā)送到另一個(gè)進(jìn)程然后等待返回。
這樣,內(nèi)核只需要對(duì)上層應(yīng)用提供一些簡(jiǎn)單的接口即可,像創(chuàng)建進(jìn)程、發(fā)送消息等,這種實(shí)現(xiàn)方式可以讓內(nèi)核盡可能簡(jiǎn)單,因?yàn)榇蟛糠謨?nèi)核程序都運(yùn)行在用戶態(tài),且運(yùn)行在不同的地址空間中,此時(shí)設(shè)備驅(qū)動(dòng)中的bug不會(huì)影響到內(nèi)核,這種操作系統(tǒng)的實(shí)現(xiàn)方式就被稱為微內(nèi)核, micro kernel。
就像宏內(nèi)核那樣,微內(nèi)核也有自己的缺點(diǎn),那就是性能。由于宏內(nèi)核的代碼都在同一個(gè)地址空間中,因此模塊間的交互可以非常簡(jiǎn)單,簡(jiǎn)單的函數(shù)調(diào)用即可,但模塊間交互對(duì)微內(nèi)核來說則可能涉及進(jìn)程間通信,看上圖,如果某個(gè)應(yīng)用程序需要請(qǐng)求使用File Server,這條鏈路涉及到:
請(qǐng)求:應(yīng)用程序 -> 內(nèi)核 -> File server
返回:Filer server -> 內(nèi)核 -> 應(yīng)用程序
每一個(gè)"->"都涉及上下文切換,而這對(duì)宏內(nèi)核來說則簡(jiǎn)單很多。
現(xiàn)實(shí)中是什么樣子?
現(xiàn)實(shí)的操作系統(tǒng)中兩種實(shí)現(xiàn)方式都很常見,Linux以及許多Unix就是典型的宏內(nèi)核,而Mac OS X 以及 Windows NT則一般認(rèn)為是微內(nèi)核,華為的鴻蒙Harmony OS則宣傳是微內(nèi)核。
圖片
有趣的是,對(duì)Linus創(chuàng)建Linux影響極大的MINIX操作系統(tǒng)也是微內(nèi)核,而Linux則是宏內(nèi)核,難怪MINIX的作者——也是操作系統(tǒng)這門課的教授說過,如果Linus是他的學(xué)生的話那么操作系統(tǒng)系統(tǒng)這門課的期末考試Linus可能很難通過。