免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 799 | 回复: 0
打印 上一主题 下一主题

linux内存管理之伙伴系统分析(大内存分配)(续三) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-11-25 18:57 |只看该作者 |倒序浏览
   min /= 2;
                   if (can_try_harder)
                            min -= min / 4;
                   min += (1protection[alloc_type];

                   if (z->free_pages
                            continue;

                   page = buffered_rmqueue(z, order, gfp_mask);
                   if (page)
                            goto got_pg;
         }

         
         do_retry = 0;
         if (!(gfp_mask & __GFP_NORETRY)) {
                   if ((order
                            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
         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 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
                   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
                   //从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);
                   //对应页目对zone的page数组中的序号
                   index = page - zone->zone_mem_map;
                   if (current_order != MAX_ORDER-1)
                            //更新分配位图
                            MARK_USED(index, current_order, area);
                   //更新zone空闲页面计数
                   zone->free_pages -= 1UL
                   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

         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:   空闲区
这段代码比较晦涩,用下形表示操作过程:

               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/65447/showart_1665804.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP