首页 > 其他分享 >bootmem 释放页到伙伴系统

bootmem 释放页到伙伴系统

时间:2023-06-04 13:07:12浏览次数:44  
标签:释放 bootmem bdata list free 伙伴 pages page


 


在前面介绍的mm_init中,其调用函数mem_init(),在这个函数中会把bootmem中空闲内存释放到伙伴系统。我们下面看bootmem中一个释放内存的


函数free_all_bootmem


 


unsigned long __init free_all_bootmem(void)
{
 unsigned long total_pages = 0;
 bootmem_data_t *bdata;
 reset_all_zones_managed_pages();
 list_for_each_entry(bdata, &bdata_list, list)
  total_pages += free_all_bootmem_core(bdata);
 totalram_pages += total_pages;
 return total_pages;
}


可以看到,函数针对系统内的所有node节点下内存进行释放,这里对链表bdata_list遍历处理,然后调用函数free_all_bootmem_core(),并且把释放的总页数记录到totalram_pages中。内核中很多函数会使用totalram_pages变量来了解系统有多少空闲内存。


 


函数free_all_bootmem_core(bootmem_data_t *bdata)是bootmem内存管理释放内存的核心函数,函数实现如下:


static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata)
{
 struct page *page;
 unsigned long *map, start, end, pages, cur, count = 0;
 if (!bdata->node_bootmem_map)
  return 0;节点node下必须关联了内存,否则释放无从谈起
 map = bdata->node_bootmem_map;获取node下内存以位图描述的指针,对于2^32即4GB内存来说,共有2^20个页,一个字节有8比特,所以这些页需要2^17字节
2^17 字节需要多少页呢,可想而知需要2^5个连续页,即32个页才能跟踪这4GB物理内存。
 start = bdata->node_min_pfn;起始页帧号
 end = bdata->node_low_pfn;结束页帧号。
 bdebug("nid=%td start=%lx end=%lx\n",
  bdata - bootmem_node_data, start, end);
 while (start < end) {
  unsigned long idx, vec;
  unsigned shift;
  idx = start - bdata->node_min_pfn;获取位图描述的index
  shift = idx & (BITS_PER_LONG - 1);看看偏移值
  /*
   * vec holds at most BITS_PER_LONG map bits,
   * bit 0 corresponds to start.
   */
  vec = ~map[idx / BITS_PER_LONG];了解位于哪个位置
  if (shift) {
   vec >>= shift;
   if (end - start >= BITS_PER_LONG)
    vec |= ~map[idx / BITS_PER_LONG + 1] <<
     (BITS_PER_LONG - shift);
  }
  /*
   * If we have a properly aligned and fully unreserved
   * BITS_PER_LONG block of pages in front of us, free
   * it in one go.
   */
  if (IS_ALIGNED(start, BITS_PER_LONG) && vec == ~0UL) {
   int order = ilog2(BITS_PER_LONG);
   __free_pages_bootmem(pfn_to_page(start), start, order);释放到伙伴系统
   count += BITS_PER_LONG;
   start += BITS_PER_LONG;
  } else {
   cur = start;
   start = ALIGN(start + 1, BITS_PER_LONG);
   while (vec && cur != start) {
    if (vec & 1) {
     page = pfn_to_page(cur);
     __free_pages_bootmem(page, cur, 0);
     count++;
    }
    vec >>= 1;
    ++cur;
   }
  }
 }
 cur = bdata->node_min_pfn;
 page = virt_to_page(bdata->node_bootmem_map);
 pages = bdata->node_low_pfn - bdata->node_min_pfn;
 pages = bootmem_bootmap_pages(pages);
 count += pages;
 while (pages--)
  __free_pages_bootmem(page++, cur++, 0);
 bdata->node_bootmem_map = NULL;
 bdebug("nid=%td released=%lx\n", bdata - bootmem_node_data, count);
 return count;
}
可以看到,最后把map数组占用的内存也释放了。
 
 
 
 
 
 
void __init __free_pages_bootmem(struct page *page, unsigned long pfn,unsigned int order)
{
 if (early_page_uninitialised(pfn))
  return;
 return __free_pages_boot_core(page, order);
}
 
 
 
 
 
static void __init __free_pages_boot_core(struct page *page, unsigned int order)
{
 unsigned int nr_pages = 1 << order;
 struct page *p = page;
 unsigned int loop;
 prefetchw(p);
 for (loop = 0; loop < (nr_pages - 1); loop++, p++) {
  prefetchw(p + 1);
  __ClearPageReserved(p);
  set_page_count(p, 0);
 }
 __ClearPageReserved(p);
 set_page_count(p, 0);
 page_zone(page)->managed_pages += nr_pages;
 set_page_refcounted(page);
 __free_pages(page, order);
}
在所有的页的相关属性设置后,最后通过__free_pages(page, order)把页释放到伙伴系统。
 
 
 
void __free_pages(struct page *page, unsigned int order)
{
 if (put_page_testzero(page)) {
  if (order == 0)
   free_hot_cold_page(page, false); 进per-cpu高速缓存队列
  else
   __free_pages_ok(page, order);释放到伙伴系统
 }
}
 
static void __free_pages_ok(struct page *page, unsigned int order)
{
 unsigned long flags;
 int migratetype;
 unsigned long pfn = page_to_pfn(page);
 if (!free_pages_prepare(page, order, true))
  return;
 migratetype = get_pfnblock_migratetype(page, pfn);
 local_irq_save(flags);
 __count_vm_events(PGFREE, 1 << order);
 free_one_page(page_zone(page), page, pfn, order, migratetype);
 local_irq_restore(flags);
}
 
函数free_hot_cold_page()把空闲内存释放到per-cpu链表。这个也是位于zone下面的pageset对象
/*
 * Free a 0-order page
 * cold == true ? free a cold page : free a hot page
 */
void free_hot_cold_page(struct page *page, bool cold)
{
 struct zone *zone = page_zone(page);
 struct per_cpu_pages *pcp;
 unsigned long flags;
 unsigned long pfn = page_to_pfn(page);
 int migratetype;
 if (!free_pcp_prepare(page))
  return;
 migratetype = get_pfnblock_migratetype(page, pfn);
 set_pcppage_migratetype(page, migratetype);
 local_irq_save(flags);
 __count_vm_event(PGFREE);
 /*
  * We only track unmovable, reclaimable and movable on pcp lists.
  * Free ISOLATE pages back to the allocator because they are being
  * offlined but treat RESERVE as movable pages so we can get those
  * areas back if necessary. Otherwise, we may have to free
  * excessively into the page allocator
  */
 if (migratetype >= MIGRATE_PCPTYPES) {
  if (unlikely(is_migrate_isolate(migratetype))) {
   free_one_page(zone, page, pfn, 0, migratetype);
   goto out;
  }
  migratetype = MIGRATE_MOVABLE;
 }
 pcp = &this_cpu_ptr(zone->pageset)->pcp;
 if (!cold)
  list_add(&page->lru, &pcp->lists[migratetype]);
 else
  list_add_tail(&page->lru, &pcp->lists[migratetype]);
 pcp->count++;
 if (pcp->count >= pcp->high) {批处理这些页,如果较多,则我们把per-cpu上面的页释放到伙伴系统。
  unsigned long batch = READ_ONCE(pcp->batch);
  free_pcppages_bulk(zone, batch, pcp);
  pcp->count -= batch;
 }
out:
 local_irq_restore(flags);
}


/*
 * Frees a number of pages from the PCP lists
 * Assumes all pages on list are in same zone, and of same order.
 * count is the number of pages to free.
 *
 * If the zone was previously in an "all pages pinned" state then look to
 * see if this freeing clears that state.
 *
 * And clear the zone's pages_scanned counter, to hold off the "all pages are
 * pinned" detection logic.
 */
从per-cpu链表上把内存释放到伙伴系统
static void free_pcppages_bulk(struct zone *zone, int count,
     struct per_cpu_pages *pcp)
{
 int migratetype = 0;
 int batch_free = 0;
 unsigned long nr_scanned;
 bool isolated_pageblocks;
 spin_lock(&zone->lock);
 isolated_pageblocks = has_isolate_pageblock(zone);
 nr_scanned = node_page_state(zone->zone_pgdat, NR_PAGES_SCANNED);
 if (nr_scanned)
  __mod_node_page_state(zone->zone_pgdat, NR_PAGES_SCANNED, -nr_scanned);
 while (count) {
  struct page *page;
  struct list_head *list;
  /*
   * Remove pages from lists in a round-robin fashion. A
   * batch_free count is maintained that is incremented when an
   * empty list is encountered.  This is so more pages are freed
   * off fuller lists instead of spinning excessively around empty
   * lists
   */
  do {
   batch_free++;
   if (++migratetype == MIGRATE_PCPTYPES)
    migratetype = 0;
   list = &pcp->lists[migratetype];
  } while (list_empty(list));
  /* This is the only non-empty list. Free them all. */
  if (batch_free == MIGRATE_PCPTYPES)
   batch_free = count;
  do {
   int mt; /* migratetype of the to-be-freed page */
   page = list_last_entry(list, struct page, lru);
   /* must delete as __free_one_page list manipulates */
   list_del(&page->lru);
   mt = get_pcppage_migratetype(page);
   /* MIGRATE_ISOLATE page should not go to pcplists */
   VM_BUG_ON_PAGE(is_migrate_isolate(mt), page);
   /* Pageblock could have been isolated meanwhile */
   if (unlikely(isolated_pageblocks))
    mt = get_pageblock_migratetype(page);
   if (bulkfree_pcp_prepare(page))
    continue;
   __free_one_page(page, page_to_pfn(page), zone, 0, mt);
   trace_mm_page_pcpu_drain(page, 0, mt);
  } while (--count && --batch_free && !list_empty(list));
 }
 spin_unlock(&zone->lock);
}

标签:释放,bootmem,bdata,list,free,伙伴,pages,page
From: https://blog.51cto.com/u_11860992/6410368

相关文章

  • 探索 GitHub Copilot:AI 代码伙伴的力量
    引言:在软件开发领域,编写高质量的代码一直是开发者们的追求。然而,代码编写过程中常常会遇到各种繁琐的细节和重复劳动,不仅浪费时间,还可能导致出错。好在现在有了GitHubCopilot,一款由人工智能驱动的代码伙伴,为开发者提供了强大的功能和更高效的编码体验。本文将介绍GitHubCopi......
  • MySQL锁查询与锁释放实操
    1.查询一个数据表中可测试数据SELECT*FROMt_wx_authorizer_infoWHEREservice_id='30127'forupdate;2.实验制造数据库锁,以下语句都先只执行第一条更新语句,然后再执行第二条更新语句的时候就会锁住--第一个事务,只执行第一条更新语句starttransaction;updatet_......
  • 武汉星起航助力跨境电商行业腾飞,合作伙伴赞誉有加
    随着国家对跨境电商行业的大力扶持,这一外贸新业态正以迅猛的步伐蓬勃发展。在这个竞争激烈的市场中,一家名为武汉星起航的公司凭借其对政策发展的敏锐洞察力和多年运营经验,成立于2020年,成功打造了全新的五对一运营教学体系,并建立了跨境电商亚马逊一站式孵化平台。通过为合作伙伴提供......
  • 跨境电商行业的领军者,武汉星起航助力合作伙伴迈向成功
    近年来,跨境电商行业迅速崛起,吸引了越来越多的企业和个人参与其中。作为一家专注于跨境电商的服务商,武汉星起航凭借其专业的运营团队和优质的服务,成为越来越多跨境卖家的选择。武汉星起航电子商务有限公司于2020年正式成立,旨在为跨境电商卖家提供一站式服务。作为专业的跨境电商服务......
  • Delphi Variant 通用类型[5] OLEVariant 的空值判定和释放
    DelphiVariant通用类型[5]OLEVariant的空值判定和释放 1、OLEVariant的空值判定varv:OLEVariant;beginv:='TaoRoy2023';ifVarIsEmpty(v)orVarIsNull(v)thenShowMessage('v为空或null.')elseShowMessage('v不为空或null.');......
  • [UE4]资源异步加载(Assets Asynchronous Loading)与内存释放(Free Memory)
    为什么需要异步加载资源,因为当一次性加载的资源较多或者单个资源较大时,普通的LoadObject()方式会阻塞引擎的主线程。 假设测试工程叫TestTD4,自定义Character叫ATestTD4Character(头文件为TestTD4Character.h)假设在Content/Assets/目录下放了三个动画文件(AnimSequence)。异步加......
  • 如何把“困在”内网的数据释放,进行安全的传输呢?
    互联网大时代,数据的生产使用与互联网紧密相关,但数据安全和网络安全却既有联系又互不相同。数据安全和网络安全的突出区别是核心主体不同,数据安全关注的数据全生命周期的安全,而网络安全则是侧重保障网络体系和网络环境的安全性。在数据传输环节,企业主要面临网络攻击和数据泄露等......
  • 2023浪潮信息分销商大会:携手伙伴共创智算分销之道
    近日,“2023浪潮信息分销商大会”在四川成都顺利举行,来自全国的百余家浪潮信息分销商伙伴出席本次大会。智算开新局·聚势迎新机,基于行业数智化转型的战略布局与实践思考,浪潮信息与分销伙伴共享共赢生态的分销之道。l 释放生态价值,共创共赢之道浪潮信息通过赋能认证,打造分销体系全......
  • 2023华为伙伴大会:ISDP发布伙伴体验中心,邀伙伴探索数智化未来
    近日,2023年华为中国合作伙伴大会于深圳国际会展中心(宝安)圆满落幕。本次大会向来自全国各个领域的1.6万多名华为新老朋友,提供一个面对面开放交流、自我展示的舞台。此次大会煤亮子、软通动力、中软国际、易宝、全采智能等多家ISDP的新老伙伴出席,一起交流行业发展与下一步合作。其中......
  • 2023华为伙伴大会:ISDP发布伙伴体验中心,邀伙伴探索数智化未来​
    近日,2023年华为中国合作伙伴大会于深圳国际会展中心(宝安)圆满落幕。本次大会向来自全国各个领域的1.6万多名华为新老朋友,提供一个面对面开放交流、自我展示的舞台。此次大会煤亮子、软通动力、中软国际、易宝、全采智能等多家ISDP的新老伙伴出席,一起交流行业发展与下一步合作。其中......