歡迎來到操作系統(tǒng)系列闯狱,采用圖解 + 大白話的形式來講解渊涝,讓小白也能看懂慎璧,幫助大家快速科普入門。
本篇文章開始探秘用戶態(tài)與內(nèi)核態(tài)跨释,雖然一般面試不會(huì)問這個(gè)胸私,但搞清楚這塊,對(duì)我們理解整個(gè)計(jì)算機(jī)系統(tǒng)是及其有意義的鳖谈,這會(huì)讓你在今后的學(xué)習(xí)中豁然開朗岁疼,你肯定會(huì)發(fā)出:“啊,原來如此的感嘆缆娃!”
內(nèi)容大綱
小故事
張三是某科技公司的初級(jí)Java開發(fā)工程師(低權(quán)限)捷绒,目前在15樓辦公碼代碼,公司提供的資源僅有一套電腦(用戶態(tài))贯要,張三想著這一線的房?jī)r(jià)暖侨,倍感壓力山大,于是給自己定下一個(gè)目標(biāo)崇渗,一定要做技術(shù)總監(jiān)字逗,在一線扎根,
奮斗B張三宅广,奮斗5年終于當(dāng)上了技術(shù)總監(jiān)(高權(quán)限)葫掉,之后張三搬到30樓,可以隨時(shí)向資源部(系統(tǒng)調(diào)用)申請(qǐng)公司各種資源與獲取公司的機(jī)密信息(內(nèi)核態(tài))乘碑,所謂是走上人生巔峰挖息。
通過這個(gè)故事,我們發(fā)現(xiàn)兽肤,低權(quán)限的資源范圍較小套腹,高權(quán)限的資源范圍更大绪抛,所謂的「用戶態(tài)與內(nèi)核態(tài)只是不同權(quán)限的資源范圍」。
C P U 指令集權(quán)限
在說用戶態(tài)與內(nèi)核態(tài)之前电禀,有必要說一下 C P U 指令集
幢码,指令集是 C P U 實(shí)現(xiàn)軟件指揮硬件執(zhí)行的媒介,具體來說每一條匯編語句都對(duì)應(yīng)了一條 C P U 指令
尖飞,而非常非常多的 C P U 指令
在一起症副,可以組成一個(gè)、甚至多個(gè)集合政基,指令的集合叫 C P U 指令集
贞铣。
同時(shí) C P U 指令集
有權(quán)限分級(jí),大家試想沮明,C P U 指令集
可以直接操作硬件的辕坝,要是因?yàn)橹噶畈僮鞯牟灰?guī)范`,造成的錯(cuò)誤會(huì)影響整個(gè)計(jì)算機(jī)系統(tǒng)的荐健。好比你寫程序酱畅,因?yàn)閷?duì)硬件操作不熟悉,導(dǎo)致操作系統(tǒng)內(nèi)核江场、及其他所有正在運(yùn)行的程序纺酸,都可能會(huì)因?yàn)椴僮魇д`而受到不可挽回的錯(cuò)誤,最后只能重啟計(jì)算機(jī)才行址否。
而對(duì)于硬件的操作是非常復(fù)雜的餐蔬,參數(shù)眾多,出問題的幾率相當(dāng)大在张,必須謹(jǐn)慎的進(jìn)行操作用含,對(duì)開發(fā)人員來說是個(gè)艱巨的任務(wù),還會(huì)增加負(fù)擔(dān)帮匾,同時(shí)開發(fā)人員在這方面也不被信任啄骇,所以操作系統(tǒng)內(nèi)核直接屏蔽開發(fā)人員對(duì)硬件操作的可能,都不讓你碰到這些 C P U 指令集
瘟斜。
針對(duì)上面的需求缸夹,硬件設(shè)備商直接提供硬件級(jí)別的支持,做法就是對(duì) C P U 指令集
設(shè)置了權(quán)限螺句,不同級(jí)別權(quán)限能使用的 C P U 指令集
是有限的虽惭,以 Inter C P U 為例,Inter把 C P U 指令集
操作的權(quán)限由高到低劃為4級(jí):
- ring 0
- ring 1
- ring 2
- ring 3
其中 ring 0 權(quán)限最高蛇尚,可以使用所有 C P U 指令集
芽唇,ring 3 權(quán)限最低,僅能使用常規(guī) C P U 指令集
,不能使用操作硬件資源的 C P U 指令集
匆笤,比如 I O
讀寫研侣、網(wǎng)卡訪問、申請(qǐng)內(nèi)存都不行炮捧,Linux系統(tǒng)僅采用ring 0 和 ring 3 這2個(gè)權(quán)限庶诡。
高情商
- ring 0被叫做內(nèi)核態(tài),完全在操作系統(tǒng)內(nèi)核中運(yùn)行
- ring 3被叫做用戶態(tài)咆课,在應(yīng)用程序中運(yùn)行
低情商
執(zhí)行內(nèi)核空間的代碼末誓,具有ring 0保護(hù)級(jí)別,有對(duì)硬件的所有操作權(quán)限书蚪,可以執(zhí)行所有
C P U 指令集
喇澡,訪問任意地址的內(nèi)存,在內(nèi)核模式下的任何異常都是災(zāi)難性的殊校,將會(huì)導(dǎo)致整臺(tái)機(jī)器停機(jī)在用戶模式下撩幽,具有ring 3保護(hù)級(jí)別,代碼沒有對(duì)硬件的直接控制權(quán)限箩艺,也不能直接訪問地址的內(nèi)存,程序是通過調(diào)用系統(tǒng)接口(System Call APIs)來達(dá)到訪問硬件和內(nèi)存宪萄,在這種保護(hù)模式下艺谆,即時(shí)程序發(fā)生崩潰也是可以恢復(fù)的,在電腦上大部分程序都是在拜英,用戶模式下運(yùn)行的
用戶態(tài)與內(nèi)核態(tài)
通關(guān)了C P U 指令集權(quán)限静汤,現(xiàn)在再說用戶態(tài)與內(nèi)核態(tài)就十分簡(jiǎn)單了,用戶態(tài)與內(nèi)核態(tài)的概念就是C P U 指令集權(quán)限的區(qū)別居凶,進(jìn)程中要讀寫 I O
虫给,必然會(huì)用到 ring 0 級(jí)別的 C P U 指令集
,而此時(shí) C P U 的指令集操作權(quán)限只有 ring 3侠碧,為了可以操作ring 0 級(jí)別的 C P U 指令集
抹估, C P U 切換指令集操作權(quán)限級(jí)別為 ring 0,C P U再執(zhí)行相應(yīng)的ring 0 級(jí)別的 C P U 指令集
(內(nèi)核代碼)弄兜,執(zhí)行的內(nèi)核代碼會(huì)使用當(dāng)前進(jìn)程的內(nèi)核棧药蜻。
PS:每個(gè)進(jìn)程都有兩個(gè)棧,分別是用戶棧與內(nèi)核棧替饿,對(duì)應(yīng)用戶態(tài)與內(nèi)核態(tài)的使用
用戶態(tài)與內(nèi)核態(tài)的空間
在內(nèi)存資源上的使用语泽,操作系統(tǒng)對(duì)用戶態(tài)與內(nèi)核態(tài)也做了限制,每個(gè)進(jìn)程創(chuàng)建都會(huì)分配「虛擬空間地址」(不懂可以參考我的另一篇文章“15分鐘视卢!一文幫小白搞懂操作系統(tǒng)之內(nèi)存”)踱卵,以Linux32位操作系統(tǒng)為例,它的尋址空間范圍是 4G
(2的32次方)据过,而操作系統(tǒng)會(huì)把虛擬控制地址劃分為兩部分惋砂,一部分為內(nèi)核空間妒挎,另一部分為用戶空間,高位的 1G
(從虛擬地址 0xC0000000 到 0xFFFFFFFF)由內(nèi)核使用班利,而低位的 3G
(從虛擬地址 0x00000000 到 0xBFFFFFFF)由各個(gè)進(jìn)程使用饥漫。
- 用戶態(tài):只能操作
0-3G
范圍的低位虛擬空間地址 - 內(nèi)核態(tài):
0-4G
范圍的虛擬空間地址都可以操作,尤其是對(duì)3-4G
范圍的高位虛擬空間地址必須由內(nèi)核態(tài)去操作 - 補(bǔ)充:
3G-4G
部分大家是共享的(指所有進(jìn)程的內(nèi)核態(tài)邏輯地址是共享同一塊內(nèi)存地址)罗标,是內(nèi)核態(tài)的地址空間庸队,這里存放在整個(gè)內(nèi)核的代碼和所有的內(nèi)核模塊,以及內(nèi)核所維護(hù)的數(shù)據(jù)
每個(gè)進(jìn)程的 4G
虛擬空間地址闯割,高位 1G
都是一樣的彻消,即內(nèi)核空間。只有剩余的 3G
才歸進(jìn)程自己使用宙拉,換句話說就是宾尚, 高位 1G
的內(nèi)核空間是被所有進(jìn)程共享的!
最后做個(gè)小結(jié)谢澈,我們通過指令集權(quán)限區(qū)分用戶態(tài)和內(nèi)核態(tài)煌贴,還限制了內(nèi)存資源的使用,操作系統(tǒng)為用戶態(tài)與內(nèi)核態(tài)劃分了兩塊內(nèi)存空間锥忿,給它們對(duì)應(yīng)的指令集使用
用戶態(tài)與內(nèi)核態(tài)的切換
相信大家都聽過這樣的話「用戶態(tài)和內(nèi)核態(tài)切換的開銷大」牛郑,但是它的開銷大在那里呢?簡(jiǎn)單點(diǎn)來說有下面幾點(diǎn)
- 保留用戶態(tài)現(xiàn)場(chǎng)(上下文敬鬓、寄存器淹朋、用戶棧等)
- 復(fù)制用戶態(tài)參數(shù),用戶棧切到內(nèi)核棧钉答,進(jìn)入內(nèi)核態(tài)
- 額外的檢查(因?yàn)閮?nèi)核代碼對(duì)用戶不信任)
- 執(zhí)行內(nèi)核態(tài)代碼
- 復(fù)制內(nèi)核態(tài)代碼執(zhí)行結(jié)果础芍,回到用戶態(tài)
- 恢復(fù)用戶態(tài)現(xiàn)場(chǎng)(上下文、寄存器数尿、用戶棧等)
實(shí)際上操作系統(tǒng)會(huì)比上述的更復(fù)雜仑性,這里只是個(gè)大概,我們可以發(fā)現(xiàn)一次切換經(jīng)歷了「用戶態(tài) -> 內(nèi)核態(tài) -> 用戶態(tài)」右蹦。
用戶態(tài)要主動(dòng)切換到內(nèi)核態(tài)虏缸,那必須要有入口才行,實(shí)際上內(nèi)核態(tài)是提供了統(tǒng)一的入口嫩实,下面是Linux整體架構(gòu)圖
從上圖我們可以看出來通過系統(tǒng)調(diào)用將Linux整個(gè)體系分為用戶態(tài)和內(nèi)核態(tài)刽辙,為了使應(yīng)用程序訪問到內(nèi)核的資源,如CPU甲献、內(nèi)存宰缤、I/O,內(nèi)核必須提供一組通用的訪問接口,這些接口就叫系統(tǒng)調(diào)用慨灭。
庫函數(shù)就是屏蔽這些復(fù)雜的底層實(shí)現(xiàn)細(xì)節(jié)朦乏,減輕程序員的負(fù)擔(dān),從而更加關(guān)注上層的邏輯實(shí)現(xiàn)氧骤,它對(duì)系統(tǒng)調(diào)用進(jìn)行封裝呻疹,提供簡(jiǎn)單的基本接口給程序員。
Shell顧名思義筹陵,就是外殼的意思刽锤,就好像把內(nèi)核包裹起來的外殼,它是一種特殊的應(yīng)用程序朦佩,俗稱命令行并思。Shell也是可編程的,它有標(biāo)準(zhǔn)的Shell 語法语稠,符合其語法的文本叫Shell腳本宋彼,很多人都會(huì)用Shell腳本實(shí)現(xiàn)一些常用的功能,可以提高工作效率仙畦。
最后來說說输涕,什么情況會(huì)導(dǎo)致用戶態(tài)到內(nèi)核態(tài)切換
系統(tǒng)調(diào)用:用戶態(tài)進(jìn)程主動(dòng)切換到內(nèi)核態(tài)的方式,用戶態(tài)進(jìn)程通過系統(tǒng)調(diào)用向操作系統(tǒng)申請(qǐng)資源完成工作慨畸,例如 fork()就是一個(gè)創(chuàng)建新進(jìn)程的系統(tǒng)調(diào)用占贫,系統(tǒng)調(diào)用的機(jī)制核心使用了操作系統(tǒng)為用戶特別開放的一個(gè)中斷來實(shí)現(xiàn),如Linux 的 int 80h 中斷先口,也可以稱為軟中斷
異常:當(dāng) C P U 在執(zhí)行用戶態(tài)的進(jìn)程時(shí),發(fā)生了一些沒有預(yù)知的異常瞳收,這時(shí)當(dāng)前運(yùn)行進(jìn)程會(huì)切換到處理此異常的內(nèi)核相關(guān)進(jìn)程中碉京,也就是切換到了內(nèi)核態(tài),如缺頁異常
中斷:當(dāng) C P U 在執(zhí)行用戶態(tài)的進(jìn)程時(shí)螟深,外圍設(shè)備完成用戶請(qǐng)求的操作后谐宙,會(huì)向 C P U 發(fā)出相應(yīng)的中斷信號(hào),這時(shí) C P U 會(huì)暫停執(zhí)行下一條即將要執(zhí)行的指令界弧,轉(zhuǎn)到與中斷信號(hào)對(duì)應(yīng)的處理程序去執(zhí)行凡蜻,也就是切換到了內(nèi)核態(tài)。如硬盤讀寫操作完成垢箕,系統(tǒng)會(huì)切換到硬盤讀寫的中斷處理程序中執(zhí)行后邊的操作等划栓。
關(guān)聯(lián)好文章推薦
關(guān)于我
Hi這里是阿星,一個(gè)熱愛技術(shù)的93年Java程序猿委煤,在公眾號(hào) 「程序猿阿星」 里將會(huì)定期分享操作系統(tǒng)堂油、計(jì)算機(jī)網(wǎng)絡(luò)、Java碧绞、分布式府框、數(shù)據(jù)庫等精品原創(chuàng)文章,2021讥邻,與您在 Be Better 的路上共同成長迫靖!。
非常感謝各位人才能 看到這里计维,創(chuàng)作不易袜香,文章有幫助可以「點(diǎn)個(gè)贊」或「分享與評(píng)論」,都是支持(莫要白嫖)鲫惶!
愿你我都能奔赴在各自想去的路上蜈首,我們下篇文章見!