本文以 32 位系統爲例介紹內核空間(kernel space)和用戶空間(user space)。html
對 32 位操做系統而言,它的尋址空間(虛擬地址空間,或叫線性地址空間)爲 4G(2的32次方)。也就是說一個進程的最大地址空間爲 4G。操做系統的核心是內核(kernel),它獨立於普通的應用程序,能夠訪問受保護的內存空間,也有訪問底層硬件設備的全部權限。爲了保證內核的安全,如今的操做系統通常都強制用戶進程不能直接操做內核。具體的實現方式基本都是由操做系統將虛擬地址空間劃分爲兩部分,一部分爲內核空間,另外一部分爲用戶空間。針對 Linux 操做系統而言,最高的 1G 字節(從虛擬地址 0xC0000000 到 0xFFFFFFFF)由內核使用,稱爲內核空間。而較低的 3G 字節(從虛擬地址 0x00000000 到 0xBFFFFFFF)由各個進程使用,稱爲用戶空間。
對上面這段內容咱們能夠這樣理解:
每一個進程的 4G 地址空間中,最高 1G 都是同樣的,即內核空間。只有剩餘的 3G 才歸進程本身使用。
換句話說就是, 最高 1G 的內核空間是被全部進程共享的!
下圖描述了每一個進程 4G 地址空間的分配狀況(此圖來自互聯網):linux
在 CPU 的全部指令中,有些指令是很是危險的,若是錯用,將致使系統崩潰,好比清內存、設置時鐘等。若是容許全部的程序均可以使用這些指令,那麼系統崩潰的機率將大大增長。
因此,CPU 將指令分爲特權指令和非特權指令,對於那些危險的指令,只容許操做系統及其相關模塊使用,普通應用程序只能使用那些不會形成災難的指令。好比 Intel 的 CPU 將特權等級分爲 4 個級別:Ring0~Ring3。
其實 Linux 系統只使用了 Ring0 和 Ring3 兩個運行級別(Windows 系統也是同樣的)。當進程運行在 Ring3 級別時被稱爲運行在用戶態,而運行在 Ring0 級別時被稱爲運行在內核態。安全
內核態與用戶態網絡
好了咱們如今須要再解釋一下什麼是內核態、用戶態:
當進程運行在內核空間時就處於內核態,而進程運行在用戶空間時則處於用戶態。
在內核態下,進程運行在內核地址空間中,此時 CPU 能夠執行任何指令。運行的代碼也不受任何的限制,能夠自由地訪問任何有效地址,也能夠直接進行端口的訪問。
在用戶態下,進程運行在用戶地址空間中,被執行的代碼要受到 CPU 的諸多檢查,它們只能訪問映射其地址空間的頁表項中規定的在用戶態下可訪問頁面的虛擬地址,且只能對任務狀態段(TSS)中 I/O 許可位圖(I/O Permission Bitmap)中規定的可訪問端口進行直接訪問。 spa
對於之前的 DOS 操做系統來講,是沒有內核空間、用戶空間以及內核態、用戶態這些概念的。能夠認爲全部的代碼都是運行在內核態的,於是用戶編寫的應用程序代碼能夠很容易的讓操做系統崩潰掉。
對於 Linux 來講,經過區份內核空間和用戶空間的設計,隔離了操做系統代碼(操做系統的代碼要比應用程序的代碼健壯不少)與應用程序代碼。即使是單個應用程序出現錯誤也不會影響到操做系統的穩定性,這樣其它的程序還能夠正常的運行(Linux 但是個多任務系統啊!)。操作系統
因此,區份內核空間和用戶空間本質上是要提升操做系統的穩定性及可用性。.net
其實全部的系統資源管理都是在內核空間中完成的。好比讀寫磁盤文件,分配回收內存,從網絡接口讀寫數據等等。咱們的應用程序是沒法直接進行這樣的操做的。可是咱們能夠經過內核提供的接口來完成這樣的任務。
好比應用程序要讀取磁盤上的一個文件,它能夠向內核發起一個 "系統調用" 告訴內核:"我要讀取磁盤上的某某文件"。其實就是經過一個特殊的指令讓進程從用戶態進入到內核態(到了內核空間),在內核空間中,CPU 能夠執行任何的指令,固然也包括從磁盤上讀取數據。具體過程是先把數據讀取到內核空間中,而後再把數據拷貝到用戶空間並從內核態切換到用戶態。此時應用程序已經從系統調用中返回而且拿到了想要的數據,能夠開開心心的往下執行了。
簡單說就是應用程序把高科技的事情(從磁盤讀取文件)外包給了系統內核,系統內核作這些事情既專業又高效。設計
對於一個進程來說,從用戶空間進入內核空間並最終返回到用戶空間,這個過程是十分複雜的。舉個例子,好比咱們常常接觸的概念 "堆棧",其實進程在內核態和用戶態各有一個堆棧。運行在用戶空間時進程使用的是用戶空間中的堆棧,而運行在內核空間時,進程使用的是內核空間中的堆棧。因此說,Linux 中每一個進程有兩個棧,分別用於用戶態和內核態。htm
下圖簡明的描述了用戶態與內核態之間的轉換:blog
既然用戶態的進程必須切換成內核態才能使用系統的資源,那麼咱們接下來就看看進程一共有多少種方式能夠從用戶態進入到內核態。歸納的說,有三種方式:系統調用、軟中斷和硬件中斷。這三種方式每一種都涉及到大量的操做系統知識,因此這裏不作展開。
接下來咱們從內核空間和用戶空間的角度看一看整個 Linux 系統的結構。它大致能夠分爲三個部分,從下往上依次爲:硬件 -> 內核空間 -> 用戶空間。以下圖所示(此圖來自互聯網):
在硬件之上,內核空間中的代碼控制了硬件資源的使用權,用戶空間中的代碼只有經過內核暴露的系統調用接口(System Call Interface)才能使用到系統中的硬件資源。其實,不光是 Linux,Windows 操做系統的設計也是大同小異。
實際上咱們能夠將每一個處理器在任何指定時間點上的活動歸納爲下列三者之一:
以上三點幾乎包括全部的狀況,好比當 CPU 空閒時,內核就運行一個空進程,處於進程上下文,但運行在內核空間。
說明:Linux 系統的中斷服務程序不在進程的上下文中執行,它們在一個與全部進程都無關的、專門的中斷上下文中執行。之因此存在一個專門的執行環境,就是爲了保證中斷服務程序可以在第一時間響應和處理中斷請求,而後快速地退出。
現代的操做系統大都經過內核空間和用戶空間的設計來保護操做系統自身的安全性和穩定性。因此在咱們閱讀有關操做系統的資料時常常遇到內核空間、用戶空間和內核態、用戶態等概念,但願本文可以幫助您理解這些基本的概念。
參考: