文章目錄
1.進程、進程切換、調度
- 系統中同時真正在運行的進程數目最多不超過CPU數目
- 確定哪個進程運行多長時間的過程稱之爲調度
2.UNIX進程
- init是進程樹的根,所有進程都直接或間接起源該進程
##@##>pstree
-
UNIX創建新進程的機制:分別是fork和exec
(1)fork技術:寫時複製(copy on write),原理:將內存複製操作延遲到父進程或子進程向某內存頁面寫入數據之前,在只讀訪問的情況下父進程和子進程可以共用同一內存頁
(2)exec將一個新程序加載到當前進程的內存中並執行。
舊程序的內存頁將刷出,其內容將替換爲新數據,然後開始執行新程序。 -
線程
進程可以看作一個正在執行的程序,線程則是與主程序並行運行的程序函數或例程 -
命名空間
每個命名空間可以包含一個特定的PID集合
3.地址空間與特權級別
-
Linux將虛擬地址空間劃分爲2個部分,內核空間和用戶空間
-
地址空間的最大長度與實際可用的物理內存數量無關,因此被稱之爲虛擬地址空間
-
各個系統進程的用戶空間是完全彼此分離的,而虛擬地址空間頂部的內核空間總是同樣的。
-
特權級別
在多處理器系統上,許多線程啓動時指定了CPU。並限制只能在某個特定的CPU上運行。從內核線程名稱之後的斜線和CPU編號可以看出這一點
[xxxx@xxxx ~]# ps fax
PID TTY STAT TIME COMMAND
2 ? S 0:01 [kthreadd]
3 ? S 0:00 \_ [migration/0]
4 ? S 0:00 \_ [ksoftirqd/0]
5 ? S 0:00 \_ [migration/0]
6 ? S 0:00 \_ [watchdog/0]
7 ? S 0:00 \_ [migration/1]
8 ? S 0:00 \_ [migration/1]
- 虛擬和物理地址空間,內核和CPU如何將實際可用的物理內存映射到虛擬地址空間的區域?
(1)使用頁表來爲物理地址分配虛擬地址。
虛擬地址關係到進程的用戶空間和內核空間,而物理地址則用來尋址實際可用的內存。
進程A的虛擬內存頁1映射到物理內存頁A,而進程B的虛擬內存頁1映射到物理內存頁5。
(2)物理內存頁經常稱作頁幀,頁則專指虛擬地址空間中的頁
(3)由於內核負責將虛擬地址空間映射到物理地址空間,因此可以決定哪些內存區域在進程之間共享,哪些不共享。
4.頁表
- 用來將虛擬地址空間映射到物理地址空間的數據結構稱爲頁表
爲什麼需要多級頁表?
(1)若使用數組,對虛擬地址空間中的每一頁,都分配一個數組項,該數組項指向與之關聯的頁幀。若爲32bit的機器,使用4KB頁,在虛擬地址空間爲4GB的前提下,則需要包含100萬項的數組。因爲虛擬地址空間的大部分區域都沒有使用,因而也沒有關聯到頁幀,那麼就可以使用功能相同,但內存用量少的模型:多級頁表
(2)全局頁目錄PGB(Page Global Directory),索引進程中的一個數組,每個進程僅有一個。PGD指向另一些數組PMD的起始地址
中間頁目錄PMD(Page Middle Directory):其數組項是指針,指向下一級數組,稱之爲頁表或目錄
(3)頁表數組PTE(Page Table Entry),用作頁表的索引。虛擬內存頁和頁幀之間的映射就此完成,頁表的數組項指向頁幀。
(4)多級頁表節省了大量的內存。每次訪問內存,通過多級頁表(逐級訪問多個數組)才能將虛擬地址轉換爲物理地址。爲了加速該過程,CPU有2種方法:內存管理單元MMU(Memory Management Unit)優化內存訪問,地址轉換中最頻繁的地址保存到TLB(地址轉換後備緩衝器,Translation Lookaside Buffer)的CPU高速緩存中
- 內存映射:在內核中大量使用,也可應用於用戶應用程序
映射方法可以將任意來源的數據傳輸到進程的虛擬地址空間,但任何修改都會自動傳輸到原數據源。
5.物理內存的分配
- 在內核分配內存時,必須記錄頁幀的已分配或空閒狀態
內核可以只分配完整的頁幀,委託用戶空間中的標準庫將內存劃分爲更小的部分,標準庫將來源於內核的頁幀拆分爲小的區域,並未進程分配內存 - 夥伴系統:分配連續頁
(1)內核對所有大小相同的夥伴(1,2,4,8。。。。)都放置到同一個列表中管理。各有8頁的一對夥伴也在相應的列表中.
如果系統需要8個頁幀,則將16個頁幀組成的塊拆分爲2個夥伴,其中一塊用於滿足應用程序的請求,而剩餘的8個頁幀則放置到對應8頁大小內存塊的類表中。
(2)如果下一個請求只需要2個連續頁幀,則由8頁組成的塊會分裂成2個夥伴,每個包含4個頁幀。
其中一塊放置回夥伴列表中,而另一個再次分裂成2個夥伴,每個包含2頁。
其中一個回到夥伴系統,另一個則傳遞給應用程序。
- slab緩存
內核無法使用標準庫函數,但是需要比完整頁幀小得多的內存塊,所以使用了slab緩存
(1)對頻繁使用的對象,內核定義了只包含了所需類型對象實例的緩存,slab緩存自動維護與夥伴系統的交互,在緩存用盡時會請求新的頁幀
(2)內核針對不同大小的對象定義了一組slab緩存。
與用戶空間編程不同的是,這些函數都增加了前綴k,eg:kmalloc,kfree
(3)頁幀的分配由夥伴系統進行,slab分配器則負責分配小內存以及提供一般性的內核緩存
- 頁面交換和頁面回收
(1)頁面交換:在內核需要更多內存時,不經常使用的頁可以寫入磁盤
(2)頁面回收:用於將內存映射被修改的內容與底層的塊設備同步
6.系統調用
- 對於所有的處理器來說,一個共同點是:用戶進程從用戶態切換到內核態,並將系統關鍵任務委派給內核執行,系統調用是必由之路
7.設備驅動程序、塊設備和字符設備
- 對外設的訪問可利用/dev目錄下的設備文件來完成,程序對設備的處理完全類似於常規的文件
- 外設可分爲以下2類:
(1)字符設備
提供連續的數據流,應用程序可以順序讀取,此類設備支持按字節/字符來讀寫數據
(2)塊設備
應用程序可以隨機訪問設備數據,程序可自行確定讀取數據的位置;
硬盤是典型的塊設備,應用程序可以尋址磁盤上的任何位置,數據的讀寫只能以塊(通常是512B)的倍數進行。與字符設備不同,塊設備並不支持基於字符的尋址。
編寫塊設備的驅動程序較字符設備要複雜得多,爲此內核廣泛使用緩存機制
8.網絡
- 在發送數據時,內核必須首先根據各個協議層的要求打包數據,然後才能發送
9.文件系統
- 虛擬文件系統層、文件系統實現和塊設備層之間的互操作
10.模塊和熱拔插
- 模塊用於在運行時,動態地向內核添加功能,如設備驅動程序、文件系統、網絡協議等
- 模塊在本質上不過是普通的程序,只是在內核空間而不是用戶空間執行而已
- 某些總線(eg:USB和FireWire)允許在系統運行時連接設備,而無需系統重啓。
在系統檢測到新設備時,通過加載對應的模塊,可以將必須的驅動程序自動添加到內核
11.緩存
- 由於內核是通過基於頁的內存映射來實現訪問塊設備的,因此緩存也是按頁組織的,也就是說整個頁都緩存起來了,故稱之爲頁緩存(page cache)
- 塊緩存已經被頁緩存取代了
12.鏈表處理
- 內核提供的標準鏈表可用於將任何類型的數據結構彼此鏈接起來。很明確,它不是類型安全的。
13.對象管理和引用計數
- (1)一般性的內核對象
- (2)對象集合
- (3)引用計數
引用計數用於檢測內核中有多少地方使用了某個對象
14.數據類型
-
(1)類型定義
內核使用typedef來定義各種數據類型,以避免依賴於體系結構相關的特性,比如,各個處理器上標準數據類型的位長可能都不見得相同。 -
(2)字節序
爲表示數字,現代計算機採用大端序( big endian)或小端序( little endian)格式 -
(3)per-cpu變量
在有若干CPU的系統上,會爲每個CPU分別創建變量的一個實例。用於某個特定CPU的實例可以通過get_cpu(name, cpu)獲得,其中smp_processor_id()可以返回當前活動處理器的ID,用作前述的cpu參數。 -
(4)訪問用戶空間
源代碼中的多處指針都標記爲__user,該標識符對用戶空間程序設計是未知的。
這是因爲內存是通過頁表映射到虛擬地址空間的用戶空間部分的,而不是由物理內存直接映射的。因此內核需要確保指針所指向的頁幀確實存在於物理內存中 -
參考:<深入Linux內核架構>