Chinaunix首页 | 论坛 | 博客
  • 博客访问: 765451
  • 博文数量: 370
  • 博客积分: 2334
  • 博客等级: 大尉
  • 技术积分: 3222
  • 用 户 组: 普通用户
  • 注册时间: 2012-05-06 16:56
文章分类

全部博文(370)

文章存档

2013年(2)

2012年(368)

分类:

2012-05-18 11:38:09

                   min /= 2;

                   if (can_try_harder)

                            min -= min / 4;

                   min += (1<protection[alloc_type];

 

                   if (z->free_pages < min)

                            continue;

 

                   page = buffered_rmqueue(z, order, gfp_mask);

                   if (page)

                            goto got_pg;

         }

 

        

         do_retry = 0;

         if (!(gfp_mask & __GFP_NORETRY)) {

                   if ((order <= 3) || (gfp_mask & __GFP_REPEAT))

                            do_retry = 1;

                   if (gfp_mask & __GFP_NOFAIL)

                            do_retry = 1;

         }

         if (do_retry) {

                   blk_congestion_wait(WRITE, HZ/50);

                   goto rebalance;

         }

 

nopage:

         if (!(gfp_mask & __GFP_NOWARN) && printk_ratelimit()) {

                   printk(KERN_WARNING "%s: page allocation failure."

                            " order:%d, mode:0x%x\n",

                            p->comm, order, gfp_mask);

                   dump_stack();

         }

         return NULL;

got_pg:

         zone_statistics(zonelist, z);

         kernel_map_pages(page, 1 << order, 1);

         return page;

}

从上面的分配过程,我们可以看到.整个分配过程是非常繁杂的,不过,大部份情况下,在第一次循环下就可以请求到内存了.上面这段代码中有一个重要的函数try_to_free_pages(),由于涉及的东西比较多,在分析完slab,swap address_space之后再对它进行详细的分析.请关注本站的更新.

到这里,alloc_pages有个大概的了解,从上面的代码可以看到,从相应的zone分配内存的接口是buffered_rmqueue().代码如下:

static struct page *

buffered_rmqueue(struct zone *zone, int order, int gfp_flags)

{

         unsigned long flags;

         struct page *page = NULL;

         int cold = !!(gfp_flags & __GFP_COLD);

 

         if (order == 0) {

         //单页面的分配

         //每个cpu都维持着一个”,”页面的内存池

                   struct per_cpu_pages *pcp;

                  

                   //取得当前cpu对应的pcp

                   pcp = &zone->pageset[get_cpu()].pcp[cold];

                   local_irq_save(flags);

                   //如果剩余页低于指定的数值,就从zone中请求一大块内存,将之放入pcp

                   if (pcp->count <= pcp->low)

                            pcp->count += rmqueue_bulk(zone, 0,

                                                        pcp->batch, &pcp->list);

                   if (pcp->count) {

                            //如果有内存剩余,直接从pcp中取从页面即可

                            page = list_entry(pcp->list.next, struct page, lru);

                            list_del(&page->lru);

                            pcp->count--;

                   }

                   local_irq_restore(flags);

                   put_cpu();

         }

 

         if (page == NULL) {

                   //多页面分配,或者是单页面的上述分配过程失败

                   spin_lock_irqsave(&zone->lock, flags);

                   page = __rmqueue(zone, order);

                   spin_unlock_irqrestore(&zone->lock, flags);

         }

 

         if (page != NULL) {

                   BUG_ON(bad_range(zone, page));

                   mod_page_state_zone(zone, pgalloc, 1 << order);

                   prep_new_page(page, order);

                   if (order && (gfp_flags & __GFP_COMP))

                            prep_compound_page(page, order);

         }

         return page;

}

Pcp结构是2.6中新加入的per-cpu结点,据统计,冷热页面缓存区的存在,使整个系统效率掉高了17%.

_rmqueue()是从相应zone中取得多页面的操作,它是整个过程的核心代码,代码如下:

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) {

                   //zone中取得相应大小的free_area

                   area = zone->free_area + current_order;

                   //如果free_area为空,则从下一个空闲区分配

                   if (list_empty(&area->free_list))

                            continue;

                   //从空闲区中分得内存

                   page = list_entry(area->free_list.next, struct page, lru);

                   //脱链

                   list_del(&page->lru);

                   //对应页目对zonepage数组中的序号

                   index = page - zone->zone_mem_map;

                   if (current_order != MAX_ORDER-1)

                            //更新分配位图

                            MARK_USED(index, current_order, area);

                   //更新zone空闲页面计数

                   zone->free_pages -= 1UL << order;

                   return expand(zone, page, index, order, current_order, area);

         }

 

         return NULL;

}

 

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 << high;

 

         while (high > low) {

                   area--;

                   high--;

                   size >>= 1;

                   BUG_ON(bad_range(zone, &page[size]));

                   list_add(&page[size].lru, &area->free_list);

                   //更正空闲区的页框位图

                   MARK_USED(index + size, high, area);

         }

         return page;

}

Expand()把剩余的内存归还给下一个空闲区.参数的含义如下:

zone:  管理区

page:  要归还内存的起始内框page

index: 在管理区中的序号

low:    欲分配的内框大小

high:   已经分配的内框大小

area:   空闲区

这段代码比较晦涩,用下形表示操作过程:

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