bootmem 释放页到伙伴系统
来源:互联网 发布:python string 倒序 编辑:程序博客网 时间:2024/06/05 04:16
在前面介绍的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 释放页到伙伴系统
- 释放页到伙伴系统之free_one_page
- linux内存模型之buddy(伙伴)系统三从bootmem到buddy的过渡
- linux内存模型之buddy(伙伴)系统三从bootmem到buddy的过渡
- Linux伙伴系统(四)--释放页
- 转载: Linux伙伴系统(四)--释放页
- Linux伙伴系统(四)--释放页
- linux内存源码分析 - 伙伴系统(释放页框)
- linux free_pages 伙伴系统释放内存过程
- linux内存伙伴算法(四:释放页)
- Linux内存管理之伙伴系统(内存释放)
- Linux内存管理之伙伴系统(内存释放)
- 内存管理之bootmem管理之释放所有bootmem内存
- 伙伴地址,伙伴系统
- 伙伴系统
- 伙伴系统
- 伙伴系统
- 伙伴系统
- java多线程
- BZOJ1135: [POI2009]Lyz
- Android开发---MediaPlayer简单音乐播放器
- Xcode工程目录下自动生成Build$DerivedData
- 蓝桥杯 ALGO-58 算法训练 字串逆序
- bootmem 释放页到伙伴系统
- wpf webbrowser注入javascript
- 安卓开发问题集锦三
- React Native FlexBox布局
- centos升级Python后,输入法出错
- 使用indexedDB(一)(翻译)
- 行为识别
- vijos 1057 盖房子
- 基于Python和Numpy的主成分分析