linux内存管理之伙伴系统以及与slab系统的调用关系

最底层接口:

__rmqueue(struct zone *zone, unsigned int order) //申请页框
	=>for (current_order = order; current_order < MAX_ORDER; ++current_order) //从当前order开始,小内存小order不够塞牙缝的
		area = zone->free_area + current_order; //瞄准,找到order配套的的area
		
		if (list_empty(&area->free_list))//当前order为空则不要浪费时间,找更大的大树傍
			continue;
			
		page = list_entry(area->free_list.next, struct page, lru); //定位到了,每个page是通过lru链接起来的,每次都是用链表头部的page,最热乎的
		
		rmv_page_order(page);//撒泡尿,这是我的地盘
		area->nr_free--;
		__mod_zone_page_state(zone, NR_FREE_PAGES, - (1UL << order));
		
		expand(zone, page, order, current_order, area);
			=>while (high > low) {//插入到不同的order链表里面
				area--;
				high--;
				size >>= 1;
				VM_BUG_ON(bad_range(zone, &page[size]));
				list_add(&page[size].lru, &area->free_list);
				area->nr_free++;
				set_page_order(&page[size], high);
			}
free_pages_bulk(struct zone *zone, int count, struct list_head *list, int order)//释放count个数目的内存
	=>while (count--)
		page = list_entry(list->prev, struct page, lru);//从屁股开始数,往前释放
		__free_one_page(page, zone, order);
			=>page_idx = page_to_pfn(page) & ((1 << MAX_ORDER) - 1);
			=>while (order < MAX_ORDER-1) {
				unsigned long combined_idx;
				struct free_area *area;
				struct page *buddy;
		
				buddy = __page_find_buddy(page, page_idx, order);
				if (!page_is_buddy(page, buddy, order))
					break;		/* Move the buddy up one level. */
		
				list_del(&buddy->lru);
				area = zone->free_area + order;
				area->nr_free--;
				rmv_page_order(buddy);
				combined_idx = __find_combined_index(page_idx, order);
				page = page + (combined_idx - page_idx);
				page_idx = combined_idx;
				order++;
			}
			=>set_page_order(page, order);//擦干尿,拍拍屁股走人
			list_add(&page->lru, &zone->free_area[order].free_list);
			zone->free_area[order].nr_free++;

中间层接口

buffered_rmqueue //在指定的内存管理区分配页框
	=>if (likely(order == 0))//页高速缓存只针对于order为0的场景
		pcp->count = rmqueue_bulk(zone, 0, pcp->batch, &pcp->list);
	=>else
		page = __rmqueue(zone, order);
 free_hot_cold_page(struct page *page, int cold)//释放页框到每个CPU页框高速缓存
	 =>if (pcp->count >= pcp->high)
		 free_pages_bulk(zone, pcp->batch, &pcp->list, 0);

最上层接口:伙伴系统的对外接口

__alloc_pages(gfp_t gfp_mask, unsigned int order, struct zonelist *zonelist)
	=>page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, order,	zonelist, ALLOC_WMARK_LOW|ALLOC_CPUSET);
		=>page = buffered_rmqueue(zonelist, zone, order, gfp_mask);
	=>wakeup_kswapd(*z, order); //如果page为0,则kswapd想办法回收页框
	=>page = get_page_from_freelist(gfp_mask, order, zonelist, alloc_flags);//再申请
	/* go through the zonelist yet again, ignoring mins */ //再申请不到的话忽略最低阈值申请
	=>page = get_page_from_freelist(gfp_mask, order, zonelist, ALLOC_NO_WATERMARKS);
	//杀死进程再看看是否有
	=>page = get_page_from_freelist(gfp_mask, order, zonelist, alloc_flags);


void __free_pages(struct page *page, unsigned int order)
	=>if (order == 0)
		free_hot_page(page);
			=>free_hot_cold_page(page, 0);
	=>else
		__free_pages_ok(page, order);
			=>free_one_page(page_zone(page), page, order);
				=>__free_one_page(page, zone, order);	

slab通关调到伙伴系统

kmem_cache_alloc
	=>__cache_alloc(cachep, flags, __builtin_return_address(0))
		=>objp = __do_cache_alloc(cachep, flags);
			=>____cache_alloc(cachep, flags);
				=>ac = cpu_cache_get(cachep);
				=>objp = cache_alloc_refill(cachep, flags);
					=>x = cache_grow(cachep, flags | GFP_THISNODE, node, NULL);//如果没有空闲的slab节点,求助buddy伙伴系统
						=>objp = kmem_getpages(cachep, local_flags, nodeid); //slab与伙伴系统的接口,与之对应的是kmem_freepages
							=> page = alloc_pages_node(nodeid, flags, cachep->gfporder);//page是物理地址
								=>__alloc_pages(gfp_mask, order, NODE_DATA(nid)->node_zonelists + gfp_zone(gfp_mask));
							=>for (i = 0; i < nr_pages; i++)
								__SetPageSlab(page + i); //设置page的slab标记位
							=>return page_address(page);//返回虚拟地址
								=>if (!PageHighMem(page))
									return lowmem_page_address(page)  //直接映射地址
										=>return __va(page_to_pfn(page) << PAGE_SHIFT);
											=>#define __page_to_pfn(page)	((unsigned long)((page) - mem_map) +  ARCH_PFN_OFFSET)
											=>#define __va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET))
												#define PAGE_OFFSET     ASM_CONST(CONFIG_KERNEL_START)
								=>pas = page_slot(page);
									=>return &page_address_htable[hash_ptr(page, PA_HASH_ORDER)];  //高端内存的页通过哈希表查找
								=>if (!list_empty(&pas->lh)) {
									struct page_address_map *pam;
							
									list_for_each_entry(pam, &pas->lh, list) { //冲突检测
										if (pam->page == page) {
											ret = pam->virtual;
											goto done;
										}
									}
								}
					=>slabp = alloc_slabmgmt(cachep, objp, offset, local_flags & ~GFP_THISNODE, nodeid);
					=>slab_map_pages(cachep, slabp, objp);//**建立page和slab的关联,使用lru指针**
						=>page = virt_to_page(addr);

						nr_pages = 1;
						if (likely(!PageCompound(page)))
							nr_pages <<= cache->gfporder;
					
						do {
							page_set_cache(page, cache);
								=>page->lru.next = (struct list_head *)cache;
							page_set_slab(page, slab);
								=>page->lru.prev = (struct list_head *)slab;
							page++;  //page的lru指针加入slab
						} while (--nr_pages);
					=>cache_init_objs(cachep, slabp);
					=>list_add_tail(&slabp->list, &(l3->slabs_free));
					=>l3->free_objects += cachep->num;

kmem_cache_destroy
	=>__kmem_cache_destroy(cachep);
		=>kmem_cache_free(&cache_cache, cachep);
			=>__cache_free(cachep, objp);
				=>cache_flusharray(cachep, ac);
					=>free_block(cachep, ac->entry, batchcount, node);
						=>slab_destroy(cachep, slabp);
							=>kmem_freepages(cachep, addr);
								=>free_pages((unsigned long)addr, cachep->gfporder);
									=>if (order == 0)
										free_hot_page(page);
											=>free_hot_cold_page(page, 0);
									else
										__free_pages_ok(page, order);
											=>__free_pages_ok(page, order);


Linux中的内存分配和释放之__alloc_pages()函数分析
https://blog.csdn.net/satanwxd/article/details/5357691

						
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值