Linux夥伴系統

2021-08-10 14:31:45 字數 4043 閱讀 3706

linux核心記憶體管理的一項重要工作就是如何在頻繁申請釋放記憶體的情況下,避免碎片的產生。linux採用夥伴系統解決外部碎片的問題,採用slab解決內部碎片的問題,在這裡我們先討論外部碎片問題。避免外部碎片的方法有兩種:一種是之前介紹過的利用非連續記憶體的分配;另外一種則是用一種有效的方法來監視記憶體,保證在核心只要申請一小塊記憶體的情況下,不會從大塊的連續空閒記憶體中擷取一段過來,從而保證了大塊記憶體的連續性和完整性。顯然,前者不能成為解決問題的普遍方法,一來用來對映非連續記憶體線性位址空間有限,二來每次對映都要改寫核心的頁表,進而就要重新整理tlb,這使得分配的速度大打折扣,這對於要頻繁申請記憶體的核心顯然是無法忍受的。因此linux採用後者來解決外部碎片的問題,也就是著名的夥伴系統。

夥伴系統的宗旨就是用最小的記憶體塊來滿足核心的對於記憶體的請求。在最初,只有乙個塊,也就是整個記憶體,假如為1m大小,而允許的最小塊為64k,那麼當我們申請一塊200k大小的記憶體時,就要先將1m的塊**成兩等分,各為512k,這兩分之間的關係就稱為夥伴,然後再將第乙個512k的記憶體塊**成兩等分,各位256k,將第乙個256k的記憶體塊分配給記憶體,這樣就是乙個分配的過程。下面我們結合示意圖來了解夥伴系統分配和**記憶體塊的過程。

1 初始化時,系統擁有1m的連續記憶體,允許的最小的記憶體塊為64k,圖中白色的部分為空閒的記憶體塊,著色的代表分配出去了得記憶體塊。

2 程式a申請一塊大小為34k的記憶體,對應的order為0,即2^0=1個最小記憶體塊

2.1 系統中不存在order 0(64k)的記憶體塊,因此order 4(1m)的記憶體塊**成兩個order 3的記憶體塊(512k)

2.2 仍然沒有order 0的記憶體塊,因此order 3的記憶體塊**成兩個order 2的記憶體塊(256k)

2.3 仍然沒有order 0的記憶體塊,因此order 2的記憶體塊**成兩個order 1的記憶體塊(128k)

2.4 仍然沒有order 0的記憶體塊,因此order 1的記憶體塊**成兩個order 0的記憶體塊(64k)

2.5 找到了order 0的記憶體塊,將其中的乙個分配給程式a,現在夥伴系統的記憶體為乙個order 0的記憶體塊,乙個order

1的記憶體塊,乙個order 2的記憶體塊以及乙個order 3的記憶體塊

3 程式b申請一塊大小為66k的記憶體,對應的order為1,即2^1=2個最小記憶體塊,由於系統中正好存在乙個order 1的內

存塊,所以直接用來分配

4 程式c申請一塊大小為35k的記憶體,對應的order為0,同樣由於系統中正好存在乙個order 0的記憶體塊,直接用來分   配

5 程式d申請一塊大小為67k的記憶體,對應的order為1

5.1 系統中不存在order 1的記憶體塊,於是將order 2的記憶體塊**成兩塊order 1的記憶體塊

5.2 找到order 1的記憶體塊,進行分配

6 程式b釋放了它申請的記憶體,即乙個order 1的記憶體塊

7 程式d釋放了它申請的記憶體

7.1 乙個order 1的記憶體塊**到記憶體當中

7.2由於該記憶體塊的夥伴也是空閒的,因此兩個order 1的記憶體塊合併成乙個order 2的記憶體塊

8 程式a釋放了它申請的記憶體,即乙個order 0的記憶體塊

9 程式c釋放了它申請的記憶體

9.1 乙個order 0的記憶體塊被釋放

9.2 兩個order 0夥伴塊都是空閒的,進行合併,生成乙個order 1的記憶體塊m

9.3 兩個order 1夥伴塊都是空閒的,進行合併,生成乙個order 2的記憶體塊

9.4 兩個order 2夥伴塊都是空閒的,進行合併,生成乙個order 3的記憶體塊

9.5 兩個order 3夥伴塊都是空閒的,進行合併,生成乙個order 4的記憶體塊

在前面的文章中已經簡單的介紹過struct zone這個結構,對於每個管理區都有自己的struct zone,而struct zone中的struct free_area則是用來描述該管理區夥伴系統的空閒記憶體塊的

[cpp]

view plain

copy

struct

zone   

[cpp]

view plain

copy

struct

free_area ;  

free_area共有max_order個元素,其中第order個元素記錄了2^order的空閒塊,這些空閒塊在free_list中以雙向鍊錶的形式組織起來,對於同等大小的空閒塊,其型別不同,將組織在不同的free_list中,nr_free記錄了該free_area中總共的空閒記憶體塊的數量。max_order的預設值為11,這意味著最大記憶體塊的大小為2^10=1024個頁框。對於同等大小的記憶體塊,每個記憶體塊的起始頁框用於鍊錶的節點進行相連,這些節點對應的著struct page中的lru域

[cpp]

view plain

copy

struct

page   

連線示意圖如下:

在2.6.24之前的核心版本中,free_area結構中只有乙個free_list陣列,而從2.6.24開始,free_area結構中存有migrate_types個free_list,這些陣列是根據頁框的移動性來劃分的,為什麼要進行這樣的劃分呢?實際上也是為了減少碎片而提出的,我們考慮下面的情況:

圖中一共有32個頁,只分配出了4個頁框,但是能夠分配的最大連續記憶體也只有8個頁框(因為夥伴系統分配出去的記憶體必須是2的整數次冪個頁框),核心解決這種問題的辦法就是將不同型別的頁進行分組。分配出去的頁面可分為三種型別:

假如上圖中大部分頁都是可移動頁,而分配出去的四個頁都是不可移動頁,由於不可移動頁插在了其他型別頁的中間,就導致了無法從原本空閒的連續記憶體區中分配較大的記憶體塊。考慮下圖的情況:

將可**頁和不可移動頁分開,這樣雖然在不可移動頁的區域當中無法分配大塊的連續記憶體,但是可**頁的區域卻沒有受其影響,可以分配大塊的連續記憶體。

核心對於遷移型別的定義如下:

[cpp]

view plain

copy

#define migrate_unmovable     0

#define migrate_reclaimable   1

#define migrate_movable       2

#define migrate_pcptypes      3 /* the number of types on the pcp lists */

#define migrate_reserve       3

#define migrate_isolate       4 /* can't allocate from here */

#define migrate_types         5

前三種型別已經介紹過

migrate_pcptypes是per_cpu_pageset,即用來表示每cpu頁框快取記憶體的資料結構中的鍊錶的遷移型別數目

migrate_reserve是在前三種的列表中都沒用可滿足分配的記憶體塊時,就可以從migrate_reserve分配

migrate_isolate用於跨越numa節點移動物理記憶體頁,在大型系統上,它有益於將物理記憶體頁移動到接近於是用該頁最頻繁地cpu

migrate_types表示遷移型別的數目

當乙個指定的遷移型別所對應的鍊錶中沒有空閒塊時,將會按以下定義的順序到其他遷移型別的鍊錶中尋找

[cpp]

view plain

copy

static

intfallbacks[migrate_types][migrate_types-1] = ,  

[migrate_reclaimable] = ,  

[migrate_movable]     = ,  

[migrate_reserve]     = , /* never used */

};  

Linux夥伴系統

夥伴系統的概述 linux核心記憶體管理的一項重要工作就是如何在頻繁申請釋放記憶體的情況下,避免碎片的產生。linux採用夥伴系統解決外部碎片的問題,採用slab解決內部碎片的問題,在這裡我們先討論外部碎片問題。避免外部碎片的方法有兩種 一種是之前介紹過的利用非連續記憶體的分配 另外一種則是用一種有...

linux記憶體管理 夥伴系統演算法

分配記憶體 釋放記憶體 兩個塊的大小相同 兩個塊的位址連續 兩個塊必須是從同乙個大塊分離出來的 linux把每個zone分成max order個free area,每個free are的大小是2的冪次方。max order的值為11,第0組大小為2 0個頁,第1組大小為2 1個頁,依次類推,最大的是...

夥伴系統演算法

如有問題,歡迎一起討論 struct free area static struct page rmqueue struct zone zone,unsigned int order return null define mark used index,order,area change bit i...