全部博文(96)
分类: LINUX
2010-09-06 11:46:17
如有问题,欢迎一起讨论:-)
struct free_area{
struct list_head free_list; /*用于连接某一大小的空闲页框*/
unsigned long *map; /*涉及到上面大小的位图,每两个的对象之间共享一位*/
};
static struct page *__rmqueue(struct zone *zone,unsigned int order)
{
struct free_area *area;
unsigned int current_order;
struct page *page;
unsigned int index;
for(current_order = order; current_order < MAX_ORDER; current_order++)
{
area = zone->area + current_order;
/*寻找2^order链表,如果此链表为空,则进行下一个链表*/
if(list_empty(&area->free_list))
continue;
/*找到free_list链表头部页框,然后删除2^current_order大小的页框*/
page = list_entry(area->free_list.next,struct page,lru);
list_del(&page->lru);
index = page - zone->zone_mem_map;
if(current_order != MAX_ORDER -1)
MARK_USED(index, current_order,area);
zone->free_pages -= 1UL << order;
/*调整free_list链表*/
return expand(zone,page,index,order,current_order,area);
}
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)
{
int *m = ( (int *)addr) + (nr >> 5); /*每个整型数据有32位图,找到第几个整型数据*/
*m ^= 1 << (nr & 31); /*给对应位置位*/
}
static inline struct page *expand(struct zone *zone, struct page *page
unsigned long index,int low,int high,struct free_area *area)
{
/*得到分配内存大小*/
unsigned long size = 1<
while(high > low){
area--; /*下一个数组链表*/
high--; /*current_order--*/
size >>= 1; /*下一个数组链表中的内存块大小*/
list_add(&page[size].lru, &area->free_list); /*加入链表*/
MARK_USED(index + size,high,area); /**/
}
return page;
}
下面是个牛人讲解位图的使用, 觉得应该是至今找的最全的了:
http://blog.csdn.net/ruixj/archive/2009/12/26/5076398.aspx
在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,
表示"伙伴"
忙,
所以位图存在的主要意义是"能够将小块内存合并成大块内存".
chinaunix网友2010-09-07 08:48:16
Download More than 1000 free IT eBooks: http://free-ebooks.appspot.com