免费注册 查看新帖 |

Chinaunix

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

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

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-10-09 22:57 |只看该作者 |倒序浏览

再来看一个多页面的释放操作,调用__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
                              for (i = 0 ; 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)
                              //取得页在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
                              //循环,合并内存
                              while (order
                                 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
                                 //它自已
                                 buddy2 = base + page_idx;
                                 //判断是否超过zone所允许的page范围
                                 BUG_ON(bad_range(zone, buddy1));
                                 BUG_ON(bad_range(zone, buddy2));
                                 //将其从现有的空闲链中脱落
                                 list_del(&buddy1->lru);
                                 //到它的上一级,判断是否有能合并的内存块
                                 mask
                                 order++;
                                 area++;
                                 index >>= 1;
                                 page_idx &= mask;
                              }
                              list_add(&(base + page_idx)->lru, &area->free_list);}

               
               
               

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

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP