免费注册 查看新帖 |

Chinaunix

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

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

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-11-25 18:58 |只看该作者 |倒序浏览
如上图所示,每一个框表示一个页面,大括号表示相应的位图.我们考虑一下以下几个问题.
1:如何知道页面在相应空闲所在的分配位图位
  结合以前讨论的伙伴系统分配位图相关知道,知道空闲区的每一组用一个位表示其分配情况,所以,在2^n的空闲链表中,每一个空闲块是2^n大小,每个位图表示 2*2^n个页.在zone中序号为index的页在2^n空闲链中相应的位图是 index/2*2^n = index>>(n+1).如上图中2^0空闲链中,1,2属于第一个位,3,4属于第二个位.
  有了上面的知识,我们就可以分析用来改变位图相应位的宏:
#define MARK_USED(index, order, area) \
     __change_bit((index) >> (1+(order)), (area)->map)
其中index是页面的序号,2^order即为area每一个空闲块的大小.这个宏对页对应的位的值进行了改变(0变成1,1变成0)
2:在一个大空闲中请求一个小空闲区,这时,大空闲的剩余部份怎么并入到小的空闲链表
如上图,如果要请求2个页面.首先它会到2^1中寻找有没有空闲页面.如果有,正好从这个链表中分配,如果没有,则要到2^2这条链表中分配,假设2^2中的第5到8是空闲的.这时会把5—8这四个页面从2^2链中脱落,更新2^2的相应分配位图.然后,再把它的半数加入到期2^1链,并更新2^1链的位.总之按照半数递减的关系放入前一个链表.按半数递减是为了把剩余内存尽量的分成大内存(因为空闲链是按2的部数增加的)
3:剩余内存归入到低链表的时候,底链表会不会合成大的空闲块?
例子如上例中.将4页面放入到2^2链的时候,有没有机会合成一个8页面空闲块?
仔细分析,不难得出:2^(n+1)每个空闲块刚好可以表示2^n位图中所表示的两个空闲块.例如上例中2^1 的第一个块,就是2^0的第位图第一个位所表示的两个空闲块.
结合前面所讨论的内容,只有同一个位图位所表示的两个空闲块都空闲的时候,才能将它合并.把剩余内存归入前一空闲链的时候,不可能满足上面所讲的要求,所以,不可能在低链上合并成高内存.
其实,只要理解了分配位图与空闲区的关系,上面的代码还是很简单的

四: free_pages()的相关实现
fastcall void __free_pages(struct page *page, unsigned int order)
{
                              //PageReserved(page):页面被保留或者没有分配出去
                              // put_page_testzero(page):把页面的引用计数减1,并判断是否为零
                              if (!PageReserved(page) && put_page_testzero(page)) {
                                 //这个页没有被使用了,可能释放到伙伴系统了
                                 if (order == 0)
                                     //单页面的释放
                                     free_hot_page(page);
                                 else
                                     //多页面的释放
                                     __free_pages_ok(page, order);
                              }
}
如前面所讲述的那样,为了提高内存管理的效率,每个cpu维持了一个单页面的缓冲区.所以当释放一个单面的时候,把它释放到缓存池就好了.
我们先看一下单页面释放的代码:
void fastcall free_hot_page(struct page *page)
{
                              free_hot_cold_page(page, 0);
}
继续跟进:
static void fastcall free_hot_cold_page(struct page *page, int cold)
{                             
                              //page所在zone
                              struct zone *zone = page_zone(page);
                              struct per_cpu_pages *pcp;
                              unsigned long flags;
                              //只有配置了HAVE_ARCH_FREE_PAGE才会起作用
                              arch_free_page(page, 0);
                              //只有配置了CONFIG_DEBUG_PAGEALLOC才会起作用
                              kernel_map_pages(page, 1, 0);
                              inc_page_state(pgfree);
                              //在”磁盘高速缓存”再来讨论mapping字段
                              if (PageAnon(page))
                                 page->mapping = NULL;
                              //DEBUG用
                              free_pages_check(__FUNCTION__, page);
                              //得到pcp
                              pcp = &zone->pageset[get_cpu()].pcp[cold];
                              local_irq_save(flags);
                              if (pcp->count >= pcp->high)
                                 //如果剩余量超过了允许的最大值,把它释放到伙伴系统
                                 pcp->count -= free_pages_bulk(zone, pcp->batch, &pcp->list, 0);
                              //将页面链入
                              list_add(&page->lru, &pcp->list);
                              //更新计数
                              pcp->count++;
                              local_irq_restore(flags);
                              put_cpu();
}
当pcp中缓存的页面超过了最大值,将pcp->batch个页面释放到伙伴系统. free_pages_bulk()在下面再分析

               
               
               

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

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP