Chinaunix首页 | 论坛 | 博客
  • 博客访问: 144379
  • 博文数量: 27
  • 博客积分: 2010
  • 博客等级: 大尉
  • 技术积分: 295
  • 用 户 组: 普通用户
  • 注册时间: 2008-06-02 22:51
文章分类
文章存档

2008年(27)

我的朋友

分类: LINUX

2008-06-07 12:28:23

再来看一个多页面的释放操作,调用__free_pages_ok(),代码如下:

//释放的起始页面:page

//页面个数:2^order

void __free_pages_ok(struct page *page, unsigned int order)

{

                              //声时并初始化一个链表

                              LIST_HEAD(list);

                              int i;

 

                              arch_free_page(page, order);

 

                              mod_page_state(pgfree, 1 << order);

                              for (i = 0 ; i < (1 << order) ; ++i)

                                 free_pages_check(__FUNCTION__, page + i);

                              list_add(&page->lru, &list);

                              kernel_map_pages(page, 1<

                              free_pages_bulk(page_zone(page), 1, &list, order);

}

它的核心处理都是在free_pages_bulk()完成的

//cout:释放的次数

//order:每次释放2^order个页面

//例如:要释放x个单页面,count = x order=0

//释放2^x大小的连续页面 count = 1 order = x

static int

free_pages_bulk(struct zone *zone, int count,

                                 struct list_head *list, unsigned int order)

{

                              unsigned long flags;

                              struct free_area *area;

                              struct page *base, *page = NULL;

                              int ret = 0;

 

                              base = zone->zone_mem_map;

                              //找到要释放大小页面的空闲链

                              area = zone->free_area + order;

                              spin_lock_irqsave(&zone->lock, flags);

                              zone->all_unreclaimable = 0;

                              zone->pages_scanned = 0;

                              //如果页面释放完了,或者循环次数已尽

                              while (!list_empty(list) && count--) {

                                 page = list_entry(list->prev, struct page, lru);

                                 /* have to delete it as __free_pages_bulk list manipulates */

                                 list_del(&page->lru);

                                 __free_pages_bulk(page, base, zone, area, order);

                                 ret++;

                              }

                              spin_unlock_irqrestore(&zone->lock, flags);

                              return ret;

}

调用__free_pages_bulk(),代码如下:

参数含义:

Page:要释放的超始page

Base:对应zone的页数组的首地址

Zone:

Area:将页面释放到此空闲区

Order:释放的连续空闲区大小

static inline void __free_pages_bulk (struct page *page, struct page *base,

                                 struct zone *zone, struct free_area *area, unsigned int order)

{

                              unsigned long page_idx, index, mask;

 

                              if (order)

                                 destroy_compound_page(page, order);

                              //假设order = 3

                              //mask = 1111 1000

                              mask = (~0UL) << order;

                              //取得页在zone中页数组中的序号

                              page_idx = page - base;

                              //~mask:0000 0111

                              //判断page_idx是不是order位对齐的

                              //结合前面alloc所分析的,不难得出在2^order大小空闲区中.

                              //空闲块的首地址必须是2^order的倍数

                              if (page_idx & ~mask)

                                 BUG();

                              //得到page在链表中的分配位图对应位,前面已经介绍过

                              index = page_idx >> (1 + order);

                             

                              //更新zone 的空闲区统计计数

                              zone->free_pages += 1 << order;

                              //循环,合并内存

                              while (order < MAX_ORDER-1) {

                                 struct page *buddy1, *buddy2;

 

                                 BUG_ON(area >= zone->free_area + MAX_ORDER);

       //判断相邻块是否空闲.前面说过,0的时候,是两者都空闲或//两者都分配出去了

                                 if (!__test_and_change_bit(index, area->map))

                                     /*

                                      * the buddy page is still allocated.

                                      */

                                     break;

 

                                 /* Move the buddy up one level. */

                              //相邻块是空闲的

                                 //它的邻居块

                                 buddy1 = base + (page_idx ^ (1 << order));

                                 //它自已

                                 buddy2 = base + page_idx;

                                 //判断是否超过zone所允许的page范围

                                 BUG_ON(bad_range(zone, buddy1));

                                 BUG_ON(bad_range(zone, buddy2));

                                 //将其从现有的空闲链中脱落

                                 list_del(&buddy1->lru);

                                 //到它的上一级,判断是否有能合并的内存块

                                 mask <<= 1;

                                 order++;

                                 area++;

                                 index >>= 1;

                                 page_idx &= mask;

                              }

                              list_add(&(base + page_idx)->lru, &area->free_list);}

 
 
 

如上图所示(标记为阴影的代表空闲块),此时系统将第4个单页表释放到伙伴系统.

首先,它会到相应大小的(2^0)的空闲链表入队.判断相邻块的空闲情况,此时,因为第三个是空闲的,所以可以合并为一块2^1的空闲块.继续判断2^1链中相邻块是否是空闲的,上图中可以将2^1的两个块合成一个大块,然后继续判断2^2中是否可以继续合并,依次类推.

上述代码中,涉及到几个位操作,分析如下:

1:得到相邻块的的起始page:

buddy1 = base + (page_idx ^ (1 << order))

如下图示:

 

根据上面的分析,可得知page_idx本身就是order位对齐的,所以,它的低order位为零.此外,再根据0与任何数异或值不变,1与数异或都相反的规律,我们可以得知,位运算结果只跟order+1位有关.据此就可以计算出它的“伙伴块”

2:得到高一级空闲链的首空闲块序号:

mask <<= 1;

page_idx &= mask;

只要按着高一级链表的order位对齐就行了

3:得到空闲块在高一级链表中对应的分配位图位

index >>= 1;

在前面分析过对应位的计算方法,在高一级空闲链中的位对应当前除二

其实这一个过程在操作系统设计中也叫“内存拼凑”,就是把剩余小内存,拼成连续的大内存,以满足某些程序的需要。

总结:

Linux采用页面为基本对应进行大内存的管理,其中26内核新加的pcp结构缓解了单页面频繁分配与释放对内存造成的压力。但是,内存分配与释放是很费时间的操作,特别是内存释放,要引发内存拼凑,因此,在编写程序的时候,尽量避免大内存的频繁操作。但仔细一想,linux内存管理还是有很多不如人意的地方:比如说释放内存的时候,效率十分低下,所以,很多公司在做嵌入式开发的时候,都自己修改了大页面的管理算法

阅读(1869) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~