Linux核心 驅動學習筆記 二

2021-08-22 09:20:03 字數 1922 閱讀 2662

linux是如何管理記憶體的?今天系統的整理一下這個問題。

在系統的初始化階段,核心根據檢測到的物理記憶體的大小,為每乙個頁面都建立乙個page結構,形成乙個page結構的陣列,並使乙個全域性量mem_map指向這個陣列。同時又按需要將這些頁面拼合成許多記憶體頁面塊,再把塊組成管理區zone,分配和釋放物理記憶體見下節。

主要用的演算法是二進位制夥伴分配器,其基本概念是:記憶體被分成了含有很多頁面的大塊,每一塊都是2 個頁面大小的方冪。如果找不到想要的塊,乙個大塊會被分成兩半,這兩半彼此就成了夥伴。其中一半被用來分配而另一半空閒。這些塊會繼續被二分直至產生乙個所需大小的塊。當乙個塊被最終釋放時,其夥伴將被檢測出來,如果它空閒則合併兩者。

分配器維護空閒頁面所組成的塊,這裡每一塊都是2 的方冪個頁面。方冪的指數被稱為階,核心對於每乙個階都維護結構陣列free_area_t,用於指向乙個空閒頁面塊的鍊錶。所以,陣列的第0 個元素將會指向具有20 個頁面大小的塊的鍊錶,第乙個元素將會是乙個具有21 個頁面大小的塊的鍊錶, 直到2max _order−1 個頁面大小的塊,max_order 的值一般為10。這消除了乙個大頁面被分開來滿足乙個小頁面塊即能滿足的要求的可能性。頁面塊通過page->list 這個線性鍊錶來維護。每乙個管理區都有乙個free_area_t 結構陣列,即free_area[max_order],它在中的定義如下所示:

typedef struct free_area_struct free_area_t;

此結構的字段:free_list 空閒頁面塊的鍊錶;map 表示一對夥伴狀態的點陣圖。

用作分配的api 函式都使用核心函式__alloc_pages(),分配通常依據乙個特定的次序進行,如果空閒塊不能滿足所

需的層,則乙個高次的塊會被分成兩個夥伴,乙個用於分配,另乙個放入低次的空閒鍊錶中。第二步決定使用哪個記憶體節點以及哪個pg_data_t。linux 使用了本地節點的分配策略,這是為了使用和執行與頁面分配程序的cpu 相關聯的記憶體庫。無論使用哪乙個api,mm/page_alloc.c 中的函式__alloc_pages()都是分配器的核心。這個函式從不被直接呼叫,它會檢查選定的管理區,看這個管理區可用的頁面數量上是否適合分配。如果這個管理區不適合,分配器將會退回到其它管理區。退回的管理區的次在啟動時由函式build_zonelists()決定。但通常是從zone_ highmem 退回到zone_ normal,從zone_ normal 再退回到zone_ dma。如果空閒頁面的數量達到pages_low 的要求,系統啟用kswapd 開始從管理區中釋放頁面。如果記憶體空間極度緊張,呼叫者將自己完成kswapd 的工作。一旦最終選定了管理區,系統會呼叫函式rmqueue()分配頁面塊,或在沒有合適大小的情況下切分高次的塊。

用於釋放頁面的api 比較簡單,它們可以幫助記憶將要釋放的頁面塊的次。夥伴分配器的乙個缺點是呼叫者必須記住最初分配的大小。用於釋放頁面的主要函式是__free_pages_ok(),它不能被直接呼叫,而是提供了函式__free_pages(), 它會首先進行一些簡單的檢查,為了探測夥伴們是不是可以合併,linux 在 free_areamap 中檢查與受影響的夥伴相對應的位。由於乙個夥伴剛剛被此函式釋放,很顯然它知道至少有乙個夥伴是空閒的。如果切

換以後點陣圖中的位是0,那麼另外乙個夥伴也肯定是空閒的,因為如果這個位是0,就意味著兩個夥伴或者同為空閒或者同被分配。如果兩個都是空閒的,系統可以合併它們。計算這個夥伴位址有乙個著名的方法[knu68]。由於分配是以2k 個塊進行的,塊的位址,或者說至少它在zone_mem_map 的起始位址將會是2k 的整次冪。最終的結論是總會有至少k 個數字的0 在位址的右邊。為了得到夥伴的位址,從右邊數的第k 位檢測。如果為0,夥伴將會翻**己的位。為了得到這個位的值,linux 引入了乙個掩碼,其計算如下:

mask=(~0《介紹mmu

核心空間 使用者空間 每個程序的對映表

虛擬記憶體的結構

如何分配和釋放虛擬記憶體 vmalloc

bootmem

slab分析

page cache

linux驅動學習 二 核心模組

因為linux 核心的整體結構非常龐大,包含的元件非常多,如何使用需要的元件呢?有一種方法是把所有的元件都編譯進核心檔案 zimage 或bzimage 但是這樣會產生兩個問題 一是生成的核心檔案過大 二是如果要新增或刪除某乙個元件,需要重新刪除編譯整個核心。於是我們需找另外一種機制讓核心檔案本身不...

Linux核心 驅動學習筆記 一

今天討論到核心啟動階段對外部裝置初始化的過程,於是粗略的看了一下相關 得到以下一些印象 未必正確,希望大家指正 1.對外部裝置初始化 出現的地方應該是 init 程序 bootloader start 彙編 decompress start kernel rest init kernel threa...

Linux核心list head學習筆記(二)

注 這個list.h 是為了配合示例程式而建的,內容來自 linux include linux list.h 和相關檔案 ifndef linux list h define linux list h struct list head define list head init name defi...