如有問題,歡迎一起討論:-)
struct free_area;
static struct page *__rmqueue(struct zone *zone,unsigned int order)
return null;
}#define mark_used(index,order,area)/
__change_bit( (index)>>(1 + (order)),(area)->map )
/*(index) >> (1 + (order))是index/(2*2^order)因為兩個大小相同的塊共享一位
所以要除以2*/
static __inline__ void __change_bit(unsigned long nr, volatile void *addr)
static inline struct page *expand(struct zone *zone, struct page *page
unsigned long index,int low,int high,struct free_area *area)
return page;
}下面是個牛人講解點陣圖的使用, 覺得應該是至今找的最全的了:
在page_init中 通過呼叫pagetable_init();建立了頁目錄表和頁表;通過呼叫zone_sizes_init(); 函式建立了node, zone,page的分層的結構,並且初始化了夥伴演算法的基本資料結構(為每個zone的free_area 的map欄位分配記憶體,並且初始化為0)。
位圖大小
free_area[ 0]
. map點陣圖大小=
(( size- 1)
/ 2)
/ 8=
( size- 1)
>
>
( 0+ 1+ 3)
free_area[ 1]
. map點陣圖大小=
(( size- 1)
/ 4)
/ 8=
( size- 1)
>
>
( 1+ 1+ 3)..
.free_area[ 9]
. map點陣圖大小=
(( size- 1)
/ 1024)
/ 8=
( size- 1)
>
>
( 9+ 1+ 3)
這裡之所以要在order的基礎上要加1,是因為每一位bit管理著兩塊記憶體塊。
然後在mem_init中呼叫__free_pages_ok來將某個zone中的所有頁框組織到free_area中。下面分析一下__free_pages_ok。
在分析之前先說一下buddy 演算法的原理:
"點陣圖中的乙個位代表相鄰的兩個夥伴頁當前被使用情況"
, 這樣1個位頂2個位來用, 就可以管理其2倍大小的size- 1個記憶體頁了.
我們知道偶數號點陣圖- a和+ 1後的緊鄰奇數號位圖- b, 它們是夥伴, 它們兩個共用點陣圖a>
> 1, 如:
下面索引的意思是第幾塊的意思.
對於order= 0, 索引0-
[ 0]
, 索引1-
[ 1] 是夥伴 ---
----
----
----
- 共用點陣圖0
索引2-
[ 2]
, 索引3-
[ 3] 是夥伴 ---
----
----
----
- 共用點陣圖1..
....
索引2* n-
[ 2* n]
, 索引2* n+ 1-
[ 2* n+ 1] 是夥伴 ---
----
----
----
- 共用點陣圖n
對於order= 1,
[ 索引0- 頁位址0, 索引1- 頁位址2=2*1] 是夥伴 ---
----
----
----
- 共用點陣圖0
[ 索引2- 頁位址4=2*2, 索引3- 頁位址6=2*3] 是夥伴 ---
----
----
----
- 共用點陣圖1..
....
[ 索引n- 頁位址2n, 索引n+ 1- 頁位址2( n+ 1)
] 是夥伴---
----
----
----
- 共用點陣圖n
對於order= 2,
[ 索引0- 頁位址0, 索引1- 頁位址4=4*1 ] 是夥伴 ---
----
----
----
- 共用點陣圖0
[ 索引2- 頁位址8=4*2, 索引3- 頁位址12=4*1] 是夥伴 ---
----
----
--- 共用點陣圖1..
....
[ 索引n- 頁位址4n, 索引n+ 1- 頁位址4( n+ 1)
] 是夥伴---
----
----
-- 共用點陣圖n
從上圖可以看到夥伴是固定的,不會變的。在order為任何大小的時候,相鄰的兩塊都是夥伴,都是0和1,2和3,4和5,.....這樣一對一對下去的。
就是說0和2絕對不會是夥伴。
所以用n個位圖就可以描述2n個單元了.
拿第80位map_bit80來說, 一開始map_bit80管理的兩個夥伴都沒有被分配出去, 這時map_bit80= 0,
由於需要現在a頁塊要被分配出去了, a分配出去的同時和1進行異或操作map_bit80= map_bit80^1= 1,
現在有兩種情況:
1. b不被分配出去, a此時需要釋放了, a開始"找朋友"
,首先計算a和朋友b對應的點陣圖, 因為map_bit80此時為1, 所以與1異或之後map_bit80= map_bit80^1= 0,
之後判斷異或之後的結果map_bit80, 如果異或結果為0, 表明a的"朋友"
, 存在,
"找朋友" 順利完成,
將a和它的朋友b合併成大空間a+ b, 放入orde= order+ 1, 上, 通過迴圈, 此時order已經加1, 繼續檢測加1後
order的朋友是否可以繼續合併, 這樣一直合併到max_order- 1為止.
2. b被分配出去, 此時a仍在使用, b對共用點陣圖map_bit80同樣進行異或操作map_bit80= map_bit80^1= 0,
3. b和a都被分配出去了, 此時其中有乙個要釋放, 比如a, 它開始"找朋友"
, 我們知道它肯定找不到朋友, 因為b也被分配出去了,
那a是怎麼知道b不存在呢, 還是異或操作, 兩個都被分配出去了, 所以當前map_bit80= 0, 經過異或之後
map_bit80= map_bit80^1= 1, 結果為1, 表示"夥伴" 不存在, 那麼不用合併, 直接**即可.
總結: 不論是"申請分配" 動作還是"釋放**" 動作, 都會對共用位圖進行異或操作, 之所以這樣來做, 目的不在於"申請分配" 上,
而是在"釋放**" 上, 當**時, 通過異或結果來判斷, 當前**頁的夥伴是否已經空閒的存在, 結果為0, 表示可以"合併成大頁"
,結果為1, 表示"夥伴" 忙, 所以位圖存在的主要意義是"能夠將小塊記憶體合併成大塊記憶體".
夥伴系統演算法
1 原理 linux的夥伴演算法把所有的空閒頁面分為10個塊組,每組中塊的大小是2的冪次方個頁面,例如,第0組中塊的大小都為20 1個頁面 第1組中塊的大小為都為21 2個頁面 第9組中塊的大小都為29 512個頁面 也就是說,每一組中塊的大小是相同的,且這同樣大小的塊形成乙個鍊錶 我們通過乙個簡單...
linux記憶體管理 夥伴系統演算法
分配記憶體 釋放記憶體 兩個塊的大小相同 兩個塊的位址連續 兩個塊必須是從同乙個大塊分離出來的 linux把每個zone分成max order個free area,每個free are的大小是2的冪次方。max order的值為11,第0組大小為2 0個頁,第1組大小為2 1個頁,依次類推,最大的是...
Linux夥伴系統
夥伴系統的概述 linux核心記憶體管理的一項重要工作就是如何在頻繁申請釋放記憶體的情況下,避免碎片的產生。linux採用夥伴系統解決外部碎片的問題,採用slab解決內部碎片的問題,在這裡我們先討論外部碎片問題。避免外部碎片的方法有兩種 一種是之前介紹過的利用非連續記憶體的分配 另外一種則是用一種有...