日期:2014-05-16 浏览次数:20710 次
__free_pages源代码详细分析如下:
fastcall void __free_pages(struct page *page, unsigned int order) { if (put_page_testzero(page)) {//一般来说,只有当页面的引用计数变为0时,才会释放该页,此处进行页面引用计数的判断 if (order == 0)//如果是释放单个页面,则释放到管理区的每CPU页面缓存中,以加快单页分配速度 free_hot_page(page); else __free_pages_ok(page, order);//否则直接释放到伙伴系统中 } } void fastcall free_hot_page(struct page *page) { free_hot_cold_page(page, 0); } free_hot_cold_page源代码详细分析如下: static void fastcall free_hot_cold_page(struct page *page, int cold) { struct zone *zone = page_zone(page);//找到页面所属的管理区 struct per_cpu_pages *pcp;//为等下访问冷热区做准备,pcp是一个中间变量 unsigned long flags; if (PageAnon(page))//说明page->mapping的第0位是1,说明该页是匿名页 page->mapping = NULL;//则使page->mapping指向NULL if (free_pages_check(page))//这个函数就是检测page的flag和mapping,_count,_mapcount这几个成员,如果有误,就会进行相应的处理 return; if (!PageHighMem(page))//如果该内存页不在高端内存域 debug_check_no_locks_freed(page_address(page), PAGE_SIZE);//则调试相关代码 arch_free_page(page, 0);//只有配置了HAVE_ARCH_FREE_PAGE才会起作用 kernel_map_pages(page, 1, 0); pcp = &zone_pcp(zone, get_cpu())->pcp[cold];//获得本页区的当前cpu,然后找到对应的热区的高速缓存内存,用pcp指针指向它 local_irq_save(flags);//禁止irq中断 __count_vm_event(PGFREE);//统计本CPU上的页面释放次数 list_add(&page->lru, &pcp->list);//把page的lru挂在pcp->list上,挂在pcp->list前面 set_page_private(page, get_pageblock_migratetype(page));//获取页面的迁移类型,并将其保存在page->private中 pcp->count++;//更新当前CPU页面缓存计数 if (pcp->count >= pcp->high) {//页面缓存中保留的页面太多,超过上限了 free_pages_bulk(zone, pcp->batch, &pcp->list, 0);//将页面缓存中的页面释放一部分到伙伴系统中 pcp->count -= pcp->batch;//更新当前CPU中页面缓存计数 } local_irq_restore(flags);//恢复中断 put_cpu();//preempt_enable()是抢占使能 } free_pages_bulk源代码详细分析如下: static void free_pages_bulk(struct zone *zone, int count, struct list_head *list, int order) { spin_lock(&zone->lock);//上锁 zone_clear_flag(zone, ZONE_ALL_UNRECLAIMABLE);//在释放页之前,先将内存区中页不可回收的标志清除 zone->pages_scanned = 0;//在上一次成功换出页之后,已扫描页计数器 while (count--) {//循环,直到把count个页面全部释放 struct page *page; VM_BUG_ON(list_empty(list)); page = list_entry(list->prev, struct page, lru);//通过pcp->list找到第一个lru,再通过lru成员找到对应的struct page /* have to delete it as __free_one_page list manipulates */ list_del(&page->lru);//lru取出后,pcp->list链表就不再指向它了,就要从链表里面移除 __free_one_page(page, zone, order);//这是释放函数的主体,下面会详细讨论 } spin_unlock(&zone->lock);//解锁 } _free_pages_ok源代码详细分析如下: static void __free_pages_ok(struct page *page, unsigned int order) { unsigned long flags; int i; int reserved = 0; for (i = 0 ; i < (1 << order) ; ++i) reserved += free_pages_check(page + i);//在释放页之前,还得先用free_pages_check函数检查页是否有错误,如果有错误就要进行相应的处理,如果没有错误,还需要记录所有页面中需要保留的页面数 if (reserved)//如果在需要释放的一段内存中有需要保留的内存页,那么该段内存就不能释放 return; if (!PageHighMem(page))//判断页是否在高端内存域中 debug_check_no_locks_freed(page_address(page),PAGE_SIZE<<order);//调试用的相关代码,还不理解,还望指点! arch_free_page(page, order);//只有配置了HAVE_ARCH_FREE_PAGE才会起作用,也不理解,还望指点 kernel_map_pages(page, 1 << order, 0); local_irq_save(flags);//禁止中断 __count_vm_events(PGFREE, 1 << order);//统计本CPU上释放的页数 free_one_page(page_zone(page), page, order);//释放函数的主体__free_one_page的封装 local_irq_restore(flags);//恢复中断 } static void free_one_page(struct zone *zone, struct page *page, int order) { spin_lock(&zone->lock);//获得管理区得自旋锁 zone_clear_flag(zone, ZONE_ALL_UNRECLAIMABLE);//在释放之前,先将内存区中页的不可回收标志清除 zone->pages_scanned = 0;//初始化在上一次成功换出页之后,已扫描页的数目。目前正在释放内存,将此清0,待回收过程随后回收时重新计数 __free_one_page(page, zone, order);//释放函数的主体 spin_unlock(&zone->lock);//解锁,有关锁的机制,自己还没有看到,后面的Blog会详细分析 } __free_one_page源代码详细分析如下: static inline void __free_one_page(struct page *page, struct zone *zone, unsigned int order) { unsigned long page_idx; int order_size = 1 << order; int migratetype = get_pageblock_migratetype(page); if (unlikely(PageCompound(page)))//要释放的页是巨页的一部分 destroy_compound_page(page, order);/