Linux内存管理之伙伴系统(内存分配)(3)

伙伴系统内存块拆分和合并

看一个辅助函数,用于伙伴系统中内存块的拆分、合并

/*   * The order of subdivision here is critical for the IO subsystem.   * Please do not alter this order without good reasons and regression   * testing. Specifically, as large blocks of memory are subdivided,   * the order in which smaller blocks are delivered depends on the order   * they're subdivided in this function. This is the primary factor   * influencing the order in which pages are delivered to the IO   * subsystem according to empirical testing, and this is also justified   * by considering the behavior of a buddy system containing a single   * large block of memory acted on by a series of small allocations.   * This behavior is a critical factor in sglist merging's success.   *   * -- wli   */    /*此函数主要用于下面这种情况:    分配函数从high中分割出去了low大小的内存;    然后要将high留下的内存块合并放到伙伴系统中;*/   static inline void expand(struct zone *zone, struct page *page,       int low, int high, struct free_area *area,       int migratetype)   {       unsigned long size = 1 << high;          while (high > low) {/*因为去掉了low的大小,所以最后肯定剩下的       是low的大小(2的指数运算)*/           area--;/*减一到order减一的area*/           high--;/*order减一*/           size >>= 1;/*大小除以2*/           VM_BUG_ON(bad_range(zone, &page[size]));           /*加到指定的伙伴系统中*/           list_add(&page[size].lru, &area->free_list[migratetype]);           area->nr_free++;/*空闲块加一*/           set_page_order(&page[size], high);/*设置相关order*/       }   }  

3.2.2 从备用链表中分配页面

/* Remove an element from the buddy allocator from the fallback list */   static inline struct page *   __rmqueue_fallback(struct zone *zone, int order, int start_migratetype)   {       struct free_area * area;       int current_order;       struct page *page;       int migratetype, i;          /* Find the largest possible block of pages in the other list */              /* 从最高阶搜索,这样可以尽量的将其他迁移列表中的大块分割,避免形成过多的碎片 */       for (current_order = MAX_ORDER-1; current_order >= order;                           --current_order) {           for (i = 0; i < MIGRATE_TYPES - 1; i++) {               /*回调到下一个migratetype*/               migratetype = fallbacks[start_migratetype][i];                  /* MIGRATE_RESERVE handled later if necessary */                                /* 本函数不处理MIGRATE_RESERVE类型的迁移链表,如果本函数返回NULL,              则上层函数直接从MIGRATE_RESERVE中分配 */               if (migratetype == MIGRATE_RESERVE)                   continue;/*访问下一个类型*/                  area = &(zone->free_area[current_order]);               /*如果指定order和类型的链表为空*/               if (list_empty(&area->free_list[migratetype]))                   continue;/*访问下一个类型*/               /*得到指定类型和order的页面基址*/               page = list_entry(area->free_list[migratetype].next,                       struct page, lru);               area->nr_free--;/*空闲块数减一*/                  /*               * If breaking a large block of pages, move all free               * pages to the preferred allocation list. If falling               * back for a reclaimable kernel allocation, be more               * agressive about taking ownership of free pages               */               if (unlikely(current_order >= (pageblock_order >> 1)) ||/* 要分割的页面是一个大页面,则将整个页面全部迁移到当前迁移类型的链表中,                  这样可以避免过多的碎片 */                                    start_migratetype == MIGRATE_RECLAIMABLE ||/* 目前分配的是可回收页面,这类页面有突发的特点,将页面全部迁移到可回收链表中,                  可以避免将其他迁移链表分割成太多的碎片 */                         page_group_by_mobility_disabled) {/* 指定了迁移策略,总是将被分割的页面迁移 */                                      unsigned long pages;                   /*移动到先前类型的伙伴系统中*/                   pages = move_freepages_block(zone, page,                                   start_migratetype);                      /* Claim the whole block if over half of it is free */                                       /* pages是移动的页面数,如果可移动的页面数量较多,                  则将整个大内存块的迁移类型修改 */                           if (pages >= (1 << (pageblock_order-1)) ||                           page_group_by_mobility_disabled)                       /*设置页面标示*/                       set_pageblock_migratetype(page,                                   start_migratetype);                      migratetype = start_migratetype;               }                  /* Remove the page from the freelists */               list_del(&page->lru);               rmv_page_order(page);                  /* Take ownership for orders >= pageblock_order */               if (current_order >= pageblock_order)//大于pageblock_order的部分设置相应标示                /*这个不太可能,因为pageblock_order为10*/                   change_pageblock_range(page, current_order,                               start_migratetype);               /*拆分和合并*/               expand(zone, page, order, current_order, area, migratetype);                  trace_mm_page_alloc_extfrag(page, order, current_order,                   start_migratetype, migratetype);                  return page;           }       }          return NULL;   }  

备用链表

/*   * This array describes the order lists are fallen back to when   * the free lists for the desirable migrate type are depleted   */    /*指定类型的链表为空时,这个数组规定    回调的到那个类型的链表*/   static int fallbacks[MIGRATE_TYPES][MIGRATE_TYPES-1] = {       [MIGRATE_UNMOVABLE]   = { MIGRATE_RECLAIMABLE, MIGRATE_MOVABLE,   MIGRATE_RESERVE },       [MIGRATE_RECLAIMABLE] = { MIGRATE_UNMOVABLE,   MIGRATE_MOVABLE,   MIGRATE_RESERVE },       [MIGRATE_MOVABLE]     = { MIGRATE_RECLAIMABLE, MIGRATE_UNMOVABLE, MIGRATE_RESERVE },       [MIGRATE_RESERVE]     = { MIGRATE_RESERVE,     MIGRATE_RESERVE,   MIGRATE_RESERVE }, /* Never used */   };  

移动到指定类型的伙伴系统中

/*将指定区域段的页面移动到指定类型的    伙伴系统中,其实就是将页面的类型做了    更改,但是是采用移动的方式     功能和上面函数类似,但是要求以   页面块方式对其*/   static int move_freepages_block(struct zone *zone, struct page *page,                   int migratetype)   {       unsigned long start_pfn, end_pfn;       struct page *start_page, *end_page;      /*如下是对齐操作,其中变量pageblock_nr_pages为MAX_ORDER-1*/       start_pfn = page_to_pfn(page);       start_pfn = start_pfn & ~(pageblock_nr_pages-1);       start_page = pfn_to_page(start_pfn);       end_page = start_page + pageblock_nr_pages - 1;       end_pfn = start_pfn + pageblock_nr_pages - 1;          /* Do not cross zone boundaries */       if (start_pfn < zone->zone_start_pfn)           start_page = page;       /*结束边界检查*/       if (end_pfn >= zone->zone_start_pfn + zone->spanned_pages)           return 0;   /*调用上面函数*/       return move_freepages(zone, start_page, end_page, migratetype);   }  

 

/*   * Move the free pages in a range to the free lists of the requested type.   * Note that start_page and end_pages are not aligned on a pageblock   * boundary. If alignment is required, use move_freepages_block()   */    /*将指定区域段的页面移动到指定类型的    伙伴系统中,其实就是将页面的类型做了 更改,但是是采用移动的方式*/   static int move_freepages(struct zone *zone,                 struct page *start_page, struct page *end_page,                 int migratetype)   {       struct page *page;       unsigned long order;       int pages_moved = 0;      #ifndef CONFIG_HOLES_IN_ZONE        /*       * page_zone is not safe to call in this context when       * CONFIG_HOLES_IN_ZONE is set. This bug check is probably redundant       * anyway as we check zone boundaries in move_freepages_block().       * Remove at a later date when no bug reports exist related to       * grouping pages by mobility       */       BUG_ON(page_zone(start_page) != page_zone(end_page));   #endif           for (page = start_page; page <= end_page;) {           /* Make sure we are not inadvertently changing nodes */           VM_BUG_ON(page_to_nid(page) != zone_to_nid(zone));              if (!pfn_valid_within(page_to_pfn(page))) {               page++;               continue;           }              if (!PageBuddy(page)) {               page++;               continue;           }              order = page_order(page);           list_del(&page->lru);/*将页面块从原来的伙伴系统链表*/           /*中删除,注意,这里不是一个页面          *而是以该页面的伙伴块*/           list_add(&page->lru,/*添加到指定order和类型下的伙伴系统链表*/               &zone->free_area[order].free_list[migratetype]);           page += 1 << order;/*移动页面数往上定位*/           pages_moved += 1 << order;/*移动的页面数*/       }          return pages_moved;   }  

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/22862.html