Linux內核子系統---內存管理子系統、進程管理子系統

Linux內核子系統

Linux內核子系統的結構在前面的博客中提到過:
這裏寫圖片描述

本次文章介紹其中的兩個主要部分:內存管理子系統 和 進程管理子系統。

Linux內存管理子系統

內存管理子系統模型圖:
這裏寫圖片描述

內存管理子系統的職能:
1、虛擬內存地址與物理內存地址之間的映射
2、物理內存的分配

地址映射管理 模型圖:
這裏寫圖片描述

若系統爲32位系統,則對應的虛擬內存的大小爲4G

地址映射管理包括兩部分:
1、虛擬內存空間分佈
2、虛擬地址轉化爲物理地址

虛擬內存的空間分佈:
(地址:0G-3G)用戶空間,運行應用程序
(地址:3G-4G)內核空間
內核空間包括:
1、3G – 3G+896MB 直接映射區
2、vmalloc區
3、永久映射區
4、固定映射區

虛擬地址轉化爲物理地址
這裏寫圖片描述

上面講到的用戶空間的四個部分在映射到物理地址時有一定的區別:
1、直接映射區:物理內存中896M以下的位置稱爲低端內存,以上的區域稱爲高端內存,在直接映射區中,若虛擬地址爲:3G+128,則物理地址就是128。直接映射區虛擬地址=3G+物理地址。
2、vmalloc區:即可訪問低端物理地址,也可訪問高端地址,沒有線性的映射特性。
3、永久映射區:固定用來訪問高端物理內存區域。
4、固定映射區:與特殊的寄存器建立映射關係。

物理內存的分配
Linux使用虛擬內存,因此程序中分配的都是虛擬地址,只有訪問虛擬地址時,纔會爲其分配物理內存。
當獲取到虛擬地址時,並不會爲其分配物理內存。
當調用malloc函數時,只是分配了一個虛擬地址,當向其中寫入數據時纔會分配物理內存。

這裏寫圖片描述

當使用 kmalloc 函數時,不僅爲其分配虛擬地址,同時還會爲其分配物理內存地址。

Linux進程管理子系統

進程與程序:
程序:
存放在磁盤上的一系列代碼和數據的可執行映像,是一個靜止的實體。
進程:
是一個執行中的程序,它是動態的實體。

進程四要素:
1、有一段程序供其執行。這段程序不一定是某個進程所專有,可以與其他進程共用。
2、有進程專用的內核空間堆棧
3、在內核中有一個task_struct數據結構,即通常所說的“進程控制塊”。有了這個數據結構,進程才能成爲內核調度的一個基本單位接受內核的調度。
4、有獨立的用戶空間

這裏寫圖片描述

Linux進程狀態:(此處比一般的三種狀態更詳細)
1、TASK_RUNNING
進程正在被CPU執行,或者已經準備就緒,隨時可以執行。當一個進程剛被創建時,就處於TASK_RUNNING狀態。

2、TASK_INTERRUPTIBLE
處於等待中的進程,待等待條件爲真時被喚醒,也可以被信號或者中斷喚醒。

3、TASK_UNINTERRUPTIBLE
處於等待中的進程,待資源有效時喚醒,但不可以由其它進程通過信號(signal)或中斷喚醒。

4、TASK_KILLABLE
Linux2.6.25新引入的進程睡眠狀態,原理類似於TASK_UNINTERRUPTIBLE,但是可以被致命信號(SIGKILL) 喚醒。

5、TASK_TRACED
正處於被調試狀態的進程。

6、TASK_DEAD
進程退出時(調用do_exit),所處的狀態。

這裏寫圖片描述

這裏寫圖片描述

Linux進程描述:
在Linux內核代碼中,線程、進程都使用結構 task_struct (sched.h) 來表示,它包含了大量描述進程/線程的信息,其中比較重要的有:

pid_t pid; //進程號
long state; //進程狀態
int prio; //進程優先級

什麼是進程調度
從就緒的進程中選出最適合的一個來執行。
進程調度涉及到的內容:
1、調度策略
2、調度時機
3、調度步驟

調度策略:
SCHED_ NORMAL(SCHED_OTHER):普通的分時進程。
SCHED_FIFO:先入先出的實時進程。
SCHED_RR:時間片輪轉的實時進程。
SCHED_BATCH:批處理進程。
SCHED_IDLE:只在系統空閒時才能夠被調度執行的進程。

調度時機:
即schedule()函數什麼時候被調用。

主動式調度:
在內核中直接調用schedule()。當進程需要等待資源等而暫時停止運行時,會把自己的狀態置於掛起(睡眠),並主動請求調度,讓出CPU。
範例:
1、current->state = TASK_INTERRUPTIBLE;
2、schedule();

被動式調度:
被動式調度又名:搶佔式調度。分爲:用戶態搶佔(Linux2.4、Linux2.6)和內核態搶佔(Linux2.6)。

用戶態搶佔:
用戶搶佔發生在:
1、從系統調用返回用戶空間。
2、從中斷處理程序返回用戶空間。

內核即將返回用戶空間的時候,如果need_resched標誌被設置,會導致schedule()被調用,即發生用戶搶佔。

  • 當某個進程耗盡它的時間片時,會設置need_resched標誌。
  • 當一個優先級更高的進程進入可執行狀態的時候,也會設置need_resched標誌。

用戶態搶佔缺陷:
進程/線程一旦運行到內核態,就可以一直執行,直到它主動放棄或時間片耗盡爲止。這樣會導致一些非常緊急的進程或線程將長時間得不到運行,降低整個系統的實時性。

改進方式:
允許系統在內核態也支持搶佔,更高優先級的進程/線程可以搶佔正在內核態運行的低優先級進程/線程。

內核態搶佔:
內核搶佔可能發生在:
1、中斷處理程序完成,返回內核空間之前。
2、當內核代碼再一次具有可搶佔性的時候,如解鎖及使能軟中斷等。

在支持內核搶佔的系統中,某些特例下是不允許搶佔的:
1、內核正在運行中斷處理
2、內核正在進行中斷上下文的Bottom Half(中斷的底半部)處理。硬件中斷返回前會執行軟中斷,此時仍然處於中斷上下文中
3、進程正持有spinlock自旋鎖、writelock/readlock讀寫鎖等,當持有這些鎖時,不應該被搶佔,否則由於搶佔將可能導致其他進程長期得不到鎖,而讓系統處於死鎖狀態。
4、內核正在執行調度程序Scheduler。搶佔的原因就是爲了進行新的調度,沒有理由將調度程序搶佔掉再運行調度程序。

搶佔計數:
爲保證Linux內核在以上情況下不會被搶佔,搶佔式內核使用了一個變量preempt_ count,稱爲內核搶佔計數。這一變量被設置在進程的thread_ info結構中。每當內核要進入以上幾種狀態時,變量preempt_ count就加1,指示內核不允許搶佔。每當內核從以上幾種狀態退出時,變量preempt_count就減1,同時進行可搶佔的判斷與調度。

調度步驟
Schedule函數工作流程如下:
1、清理當前運行中的進程;
2、選擇下一個要運行的進程;
3、設置新進程的運行環境;
4、進程上下文切換 。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章