核心中alloc_pages系列頁框分配函式都是基於夥伴演算法實現的,這些函式最終都會呼叫夥伴演算法的入口函式buffered_rmqueue()。
linux核心管理物理記憶體有三種方式,其一就是經典的夥伴演算法。但是夥伴演算法分配物理記憶體的基本單位是頁框,因此核心又引入了slab機制,基於此機制實現的物理記憶體分配器可以快速有效的分配小於頁框的物理記憶體,並且可以有效避免內部碎片。另外,核心常常會申請單個頁框大小的物理記憶體,因此核心又引入了per-cpu機制,該機制專門用於快速分配單個頁框。
其實buffered_rmqueue()函式仍然沒有進行真正的頁框分配,該函式首先判斷分配階是否為0,如果是則啟用per-cpu機制來分配物理記憶體,否則呼叫__rmqueue()。
static struct page *__rmqueue(struct zone *zone, unsigned int order,
int migratetype)
}trace_mm_page_alloc_zone_locked(page, order, migratetype);
return page;
}傳遞到此函式中的zone表示夥伴演算法將從該記憶體管理區中分配頁框,order即分配階,migratetype表示遷移型別。該函式首選__rmqueue_smallest()進行記憶體分配,如果在指定的遷移型別上分配失敗後,再選用其他備用的遷移列表進行記憶體分配,該過程通過__rmqueue_fallback()完成。總之核心總是在竭盡全力保證滿足分配記憶體的請求。
該函式的實現比較簡單,從當前指定的分配階到最高分配階依次進行遍歷。在每次遍歷的分配階煉表中,根據引數migratetype選擇正確的遷移佇列。根據以上的限定條件,當選定乙個頁框塊鍊錶後,只要該煉表不為空,就說明可以分配該分配階對應的頁框塊。
一旦選定在當前遍歷的分配階煉表上分配頁框,那麼就通過list_entry()將該頁框塊從鍊錶上移除。然後將頁框塊首頁框的pg_buddy標誌刪除,刪除該標誌說明當前頁框塊已經不屬於夥伴鍊錶。並且將該首頁框描述符中的priveate置0,該字段中本來儲存的是其所處頁框塊的分配階。以上這個過程通過rmv_page_order()完成。此外,還要更新頁框塊鍊錶nr_free的值。
static inline
struct page *__rmqueue_smallest(struct zone *zone, unsigned int order,
int migratetype)
return null;
}static inline void rmv_page_order(struct page *page)
__rmqueue_smallest()內部還有乙個重要的函式expand()。進入該函式的條件是當所申請的分配階order小於當前選中的分配階current_order,也就是說指定的分配階煉表中沒有空閒的頁框塊,只能選用較大的頁框塊。因此,expand()必須按照夥伴演算法的**原理將比較大的頁框塊分割成較小的塊。
3.expand()
**函式的實現也是顯而易見的,它完全遵照夥伴演算法的**原理。這裡有兩個分配階,乙個是申請頁框時指定的low,乙個是在上級函式中遍歷時所選定的high。該函式從high分配階開始遞減向low遍歷,也就是從較大的頁框塊開始依次**。
比如high為4,而low為2。那麼第一遍歷時,將大小為16(分配階為4)的頁框塊乙份為2。通過list_add()將後面的8個連續頁框塊加入下級鍊錶(分配階為3),下級鍊錶通過將area指標自減即可得到,後8個頁框塊的指標也通過page+size獲得,而page仍然指向最初的頁框塊首頁框。此時還要對分配階為3的鍊錶更新nr_free,以及通過set_page_order()對後8個頁框塊設定一些標誌。
第二次遍歷將前面8個頁框塊繼續一分為二,將後4個頁框塊加入area所指向的下級鍊錶(分配階為2)。第三次遍歷時,迴圈條件已經不再滿足,因此返回前4個頁框塊首頁框的描述符位址page。
static inline void expand(struct zone *zone, struct page *page,
int low, int high, struct free_area *area,
int migratetype)
}static inline void set_page_order(struct page *page, int order)
夥伴系統(演算法) 記憶體分配技術(2)
記憶體管理中的分割槽分配方法 1 夥伴系統 演算法 記憶體分配技術 2 分配核心記憶體 buddy系統和slab系統 3 靜態分割槽方案受固定活躍程序數的限制,並且空間的使用也可能不是最優的。夥伴系統是乙個記憶體分配與管理演算法,該演算法管理的記憶體以2的冪次增長。假設記憶體大小是2,假設需求s大小...
Linux頁框 夥伴演算法以及slab機制
無論是上層應用還是作業系統核心開發,記憶體問題都是我們所需要關注的。我們來看看linux核心管理和分配機制。夥伴演算法 夥伴演算法從物理連續的大小固定的段上進行分配。從這個段上分配記憶體,採用 2 的冪分配器來滿足請求分配單元的大小為 2 的冪 4kb 8kb 16kb 等 請求單元的大小如不適當,...
夥伴分配器的乙個極簡實現
提起buddy system相信很多人不會陌生,它是一種經典的記憶體分配演算法,大名鼎鼎的linux底層的記憶體管理用的就是它。這裡不 核心這麼複雜實現,而僅僅是將該演算法抽象提取出來,同時給出乙份及其簡潔的原始碼實現,以便定製擴充套件。夥伴分配的實質就是一種特殊的 分離適配 即將記憶體按2的冪進行...