深刻Linux內核架構第一章筆記

1. Linux是多任務系統, 支持併發執行若干進程,系統同時真正運行的進程數目不超過CPU的數量,所以內核會按照時間間隔在不一樣進程之間切換。 java

2.肯定那個進程運行多長時間的過程稱爲調度。 node

3.內核啓動init進程做爲第一個進程,該進程負責進一步的系統初始化操做,並顯示登錄提示符或登錄界面。所以init是進程樹的根,全部進程都直接或間接來源次進程。 linux

4. 進程不是內核支持的惟一一種程序執行方式,除此之外,還有線程。 算法

5. Linux將虛擬地址空間分爲兩部分,內核空間和用戶空間。 編程

6. Intel 將處理器分爲4個特權狀態,ring0 ~ ring3, 可是Linux只使用了兩種狀態:用戶態和核心態。 數組

7。用來將虛擬地址空間映射到物理地址空間的數據結構稱爲頁表。 緩存

8。爲了減小頁表的大小並允許忽略不須要的區域,Linux將虛擬地址劃分爲多個部分,也就是多級頁表。 安全

 

PGD (Page Global Directory) àPMD (Page Middle Directory)àPTE (Page Table Entry) àoffset 網絡

9. 多級頁表節省了大量的內存,可是它的缺點是須要逐級訪問多個數組才能將虛擬地址轉換爲物理地址,耗時較長。因而CPU經過MMU來優化訪問操做及利用TLB(Translation lookaside buffer)來加速。 數據結構

10. 內核不少時候須要分配連續頁,爲快速檢測內存中的連續區域,通常狀況下用夥伴系統,也就是空閒內存兩兩分組,每組中的兩塊內存稱爲夥伴。另一種方法就是slab。

11.slab主要針對常常釋放並分配的內存對象,須要對象時,能夠快速分配。雖然slab的性能很好,可是對嵌入式系統而言,開銷太大,因而有了一個 slab 模擬層,名爲 SLOB。這個 slab 的替代品在小型嵌入式 Linux 系統中具備優點,可是即便它保存了 512KB 內存,依然存在碎片和難於擴展的問題。在禁用 CONFIG_SLAB 時,內核會回到這個 SLOB 分配器中

 

Linux 的slab 可有三種狀態:

  • 滿的:slab 中的全部對象被標記爲使用。
  • 空的:slab 中的全部對象被標記爲空閒。
  • 部分:slab 中的對象有的被標記爲使用,有的被標記爲空閒。

    與傳統的內存管理模式相比, slab 緩存分配器提供了不少優勢。

  • 內核一般依賴於對小對象的分配,它們會在系統生命週期內進行無數次分配。
  • slab 緩存分配器經過對相似大小的對象進行緩存而提供這種功能,從而避免了常見的碎片問題。
  • slab 分配器還支持通用對象的初始化,從而避免了爲同一目的而對一個對象重複進行初始化。
  • slab 分配器還能夠支持硬件緩存對齊和着色,這容許不一樣緩存中的對象佔用相同的緩存行,從而提升緩存的利用率並得到更好的性能。

     

隨着大規模多處理器系統和NUMA系統的普遍應用,slab分配器逐漸暴露出自身嚴重的不足:

  • 較多複雜的隊列管理。在slab分配器中存在衆多的隊列,例如針對處理器的本地緩存隊列,slab中空閒隊列,每一個slab處於一個特定狀態的隊列之中。因此,管理太費勁了。
  • slab管理數據和隊列的存儲開銷比較大。每一個slab須要一個struct slab數據結構和一個管理者kmem_bufctl_t型的數組。當對象體積較小時,該數組將形成較大的開銷(好比對象大小爲32字節時,將浪費1/8空間)。爲了使得對象在硬件告訴緩存中對齊和使用着色策略,還必須浪費額外的內存。同時,緩衝區針對節點和處理器的隊列也會浪費很多內存。測試代表在一個1000節點/處理器的大規模NUMA系統中,數GB內存被用來維護隊列和對象引用。
  • 緩衝區回收比較複雜。
  • 對NUMA的支持很是複雜。slab對NUMA的支持基於物理頁框分配器,沒法細粒度的使用對象,所以不能保證處理器級的緩存來自同一節點(這個我暫時不太懂)。
  • 冗餘的partial隊列。slab分配器針對每一個節點都有一個partial隊列,隨着時間流逝,將有大量的partial slab產生,不利於內存的合理使用。
  • 性能調優比較困難。針對每一個slab能夠調整的參數比較複雜,並且分配處理器本地緩存時,不得不使用自旋鎖。
  • 調試功能比較難於使用。

12. SLOB是slab在小型嵌入式系統上的一個模擬器,目的是爲了下降資源開銷。

13. 內存管理其實是一種關於權衡的零和遊戲。您能夠開發一種使用少許內存進行管理的算法,可是要花費更多時間來管理可用內存。也能夠開發一個算法來有效地管理內存,但卻要使用更多的內存。最終,特定應用程序的需求將促使對這種權衡作出選擇。

每一個內存管理器都使用了一種基於堆的分配策略。在這種方法中,大塊內存(稱爲 堆)用來爲用戶定義的目的提供內存。當用戶須要一塊內存時,就請求給本身分配必定大小的內存。堆管理器會查看可用內存的狀況(使用特定算法)並返回一塊內存。搜索過程當中使用的一些算法有 first-fit(在堆中搜索到的第一個知足請求的內存塊 )和 best-fit(使用堆中知足請求的最合適的內存塊)。當用戶使用完內存後,就將內存返回給堆。這種基於堆的分配策略的根本問題是碎片(fragmentation)。

14. 給出了 slab 結構的高層組織結構。在最高層是 cache_chain,這是一個 slab 緩存的連接列表。這對於 best-fit 算法很是有用,能夠用來查找最適合所須要的分配大小的緩存(遍歷列表)。cache_chain 的每一個元素都是一個 kmem_cache 結構的引用(稱爲一個 cache)。它定義了一個要管理的給定大小的對象池。

15. proc 文件系統提供了一種簡單的方法來監視系統中全部活動的 slab 緩存。這個文件稱爲 /proc/slabinfo,它除了提供一些能夠從用戶空間訪問的可調整參數以外,還提供了有關全部 slab 緩存的詳細信息。

16. 全局變量jiffies用來記錄自系統啓動以來產生的節拍的總數。啓動時,內核將該變量初始化爲0,此後,每次時鐘中斷處理程序都會增長該變量的值。一秒內時鐘中斷的次數等於Hz,因此jiffies一秒內增長的值也就是Hz。 系統運行時間以秒爲單位,等於jiffies/Hz。

注意,jiffies類型爲無符號長整型(unsigned long),其餘任何類型存放它都不正確。

Jiffies_64 是64爲系統。

17.系統調用是用戶進程和內核交互的經典方法。主要包括進程管理, 信號,文件,目錄和文件系統,保護機制及定時器函數。

18.萬物皆文件,外設包括字符設備,塊設備及網絡設備。

19.Linux支持的文件系統有:Ext2, Ext3, ResierFS,XFS, VFAT等。

Ext2基於inode, 也就是說每一個文件都構造了一個單獨的管理結構,稱爲inode。

VFS(Virtual File System or Virtual File Switch)將底層文件系的具體信息和應用層隔離開來。

20. 模塊是個普通的程序,只不過運行在內核空間而不是用戶空間。模塊特性使得內核能夠支持種類繁多的設備,而不會形成內核自身膨脹。

21.因爲內核是基於頁的內存映射來實現訪問設備的,緩存也是按照頁的組織緩存起來的,也就是頁緩存。

22.內核提供的標準鏈表能夠將任何類型的數據結構鏈接起來,固然這就意味着此鏈表不是類型安全的。此鏈表的機構存在於include/list.h下。

23. kobject是組成設備模型的基本結構。相似於java中的object類,是全部用來描述設備模型的數據結構的基類,它嵌入於全部的描述設備模型的容器對象中,例如bus,devices,drivers等。這些容器經過kobject連接起來,造成一個樹狀結構,這個樹狀結構與/sys中是一一對應的。須要注意的是,並非說每個kobject對象都須要在sysfs中表示,可是每個被註冊到系統中的kset都會被添加到sysfs文件系統中,一個kset對象就對應一個/sys中的一個目錄,kset中的每個kobject成員,都對應sysfs中一個文件或者一個目錄。

目前爲止,Kobject主要提供以下功能:

  • 經過parent指針,能夠將全部Kobject以層次結構的形式組合起來。
  • 使用一個引用計數(reference count),來記錄Kobject被引用的次數,並在引用次數變爲0時把它釋放(這是Kobject誕生時的惟一功能)。
  • 和sysfs虛擬文件系統配合,將每個Kobject及其特性,以文件的形式,開放到用戶空間。

    Kobject是基本數據類型,每一個Kobject都會在"/sys/"文件系統中以目錄的形式出現。

    Ktype表明Kobject(嚴格地講,是包含了Kobject的數據結構)的屬性操做集合(因爲通用性,多個Kobject可能共用同一個屬性操做集,所以把Ktype獨立出來了)。注3:在設備模型中,ktype的命名和解釋,都很是抽象,理解起來很是困難,後面會詳細說明。

    Kset是一個特殊的Kobject(所以它也會在"/sys/"文件系統中以目錄的形式出現),它用來集合類似的Kobject(這些Kobject能夠是相同屬性的,也能夠不一樣屬性的)。

Linux內核中有大量的驅動,而這些驅動每每具備相似的結構,根據面向對象的思想,咱們就能夠將這些共同的部分提取爲父類,這個父類就是kobject,也就是驅動編程中使用的.ko文件的由來,下面這張圖是我根據內核源碼的kobject繪製的簡單的UML圖,從中能夠看出,kobject包含了大量的設備必須的信息,而三大類設備驅動都須要包含這個kobject結構,也就是"繼承"自kobject。一個kobject對象就對應sys目錄中的一個設備。
內核源碼中的kobject結構定義以下

//include/linux/kobject.h

struct kobject {

const char *name;

struct list_head entry;

struct kobject *parent;

struct kset *kset;

struct kobj_type *ktype;

struct kernfs_node *sd; /* sysfs directory entry */

struct kref kref;

#ifdef CONFIG_DEBUG_KOBJECT_RELEASE

struct delayed_work release;

#endif

unsigned int state_initialized:1;

unsigned int state_in_sysfs:1;

unsigned int state_add_uevent_sent:1;

unsigned int state_remove_uevent_sent:1;

unsigned int uevent_suppress:1;

};

這個結構中,

struct kobject
name表示kobject對象的名字,對應sysfs下的一個目錄。
entry是kobject中插入的head_list結構,
parent是指向當前kobject父對象的指針,體如今sys結構中就是包含當前kobject對象的目錄對象,
kset表示當前kobject對象所屬的集合,
ktype表示當前kobject的類型。
sd用於表示VFS文件系統的目錄項,是設備與文件之間的橋樑,sysfs中的符號連接就是經過kernfs_node內的聯合體實現的。
kref是對kobject的引用計數,當引用計數爲0時,就回調以前註冊的release方法釋放該對象。
state_initialized:1初始化標誌位,在對象初始化時被置位,表示對象是否已經被初始化。
state_in_sysfs:1表示kobject對象在sysfs中的狀態,在對應目錄中被建立則置1,不然爲0。
state_add_uevent_sent:1是添加設備的uevent事件是否發送標誌,添加設備時會向用戶空間發送uevent事件,請求新增設備。
state_remove_uevent_sent:1是刪除設備的uevent事件是否發送標誌,刪除設備時會向用戶空間發送uevent事件,請求卸載設備

kobject,kset是Linux設備管理中的基本結構體,但在實際操做中咱們幾乎不會實際操做這些結構,由於他們自己並不具備針對某一個具體設備或驅動的信息,在Linux內核中,這兩個結構都是被包含具體的設備結構中,好比cdev,gendisk等,從面向對象的角度考慮,就是每一類設備均可以看做這兩個結構的子類。
經過上面的分析,咱們能夠看出這三者之間的關係,並畫出下面的結構框圖,sysfs中的上目錄結構就是根據kset之間的數據組織方式進行呈現的。

 

總結,Ktype以及整個Kobject機制的理解。 Kobject的核心功能是:保持一個引用計數,當該計數減爲0時,自動釋放(由本文所講的kobject模塊負責) Kobject所佔用的meomry空間。這就決定了Kobject必須是動態分配的(只有這樣才能動態釋放)。 而Kobject大多數的使用場景,是內嵌在大型的數據結構中(如Kset、device_driver等),所以這些大型的數據結構,也必須是動態分配、動態釋放的。那麼釋放的時機是什麼呢?是內嵌的Kobject釋放時。可是Kobject的釋放是由Kobject模塊自動完成的(在引用計數爲0時),那麼怎麼一併釋放包含本身的大型數據結構呢? 這時Ktype就派上用場了。咱們知道,Ktype中的release回調函數負責釋放Kobject(甚至是包含Kobject的數據結構)的內存空間,那麼Ktype及其內部函數,是由誰實現呢?是由上層數據結構所在的模塊!由於只有它,才清楚Kobject嵌在哪一個數據結構中,並經過Kobject指針以及自身的數據結構類型,找到須要釋放的上層數據結構的指針,而後釋放它。 因此,每個內嵌Kobject的數據結構,例如kset、device、device_driver等等,都要實現一個Ktype,並定義其中的回調函數。同理,sysfs相關的操做也同樣,必須通過ktype的中轉,由於sysfs看到的是Kobject,而真正的文件操做的主體,是內嵌Kobject的上層數據結構! Kobject是面向對象的思想在Linux kernel中的極致體現,但C語言的優點卻不在這裏,因此Linux kernel須要用比較巧妙(也很囉嗦)的手段去實現,

相關文章
相關標籤/搜索