linux java 释放,Linux伙伴系统(四)--释放页

确定页是空闲的后,再判断要释放多少个页面,如果是单个页面则将该页作为热页释放到pcp中,如果是多页则释

放到伙伴系统中

void free_hot_page(struct page *page)

{

trace_mm_page_free_direct(page, 0);

free_hot_cold_page(page, 0);

}

free_hot_page是free_hot_cold_page的封装 static void free_hot_cold_page(struct page *page, int cold)

{

struct zone *zone = page_zone(page);

struct per_cpu_pages *pcp;

unsigned long flags;

int migratetype;

int wasMlocked = __TestClearPageMlocked(page);

kmemcheck_free_shadow(page, 0);

if (PageAnon(page))

page->mapping = NULL;

if (free_pages_check(page))

return;

if (!PageHighMem(page)) {

debug_check_no_locks_freed(page_address(page), PAGE_SIZE);

debug_check_no_obj_freed(page_address(page), PAGE_SIZE);

}

arch_free_page(page, 0);

kernel_map_pages(page, 1, 0);

/*获取对应的pcp结构*/

pcp = &zone_pcp(zone, get_cpu())->pcp;

/*获取迁移类型*/

migratetype = get_pageblock_migratetype(page);

set_page_private(page, migratetype);

local_irq_save(flags);

if (unlikely(wasMlocked))

free_page_mlock(page);

__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

*/

/*只有不可移动页,可回收页和可移动页才能放到每CPU页框高速缓存中,如果

迁移类型不属于这个范围,则要将该页释放回伙伴系统*/

if (migratetype >= MIGRATE_PCPTYPES) {

if (unlikely(migratetype == MIGRATE_ISOLATE)) {

free_one_page(zone, page, 0, migratetype);

goto out;

}

migratetype = MIGRATE_MOVABLE;

}

if (cold)/*冷页插入表尾*/

list_add_tail(&page->lru, &pcp->lists[migratetype]);

else /*热页插入表头*/

list_add(&page->lru, &pcp->lists[migratetype]);

pcp->count++;

/*如果pcp中的页面数超过了high,则释放2^batch个单页给伙伴系统*/

if (pcp->count >= pcp->high) {

free_pcppages_bulk(zone, pcp->batch, pcp);

pcp->count -= pcp->batch;

}

out:

local_irq_restore(flags);

put_cpu();

}

伙伴系统的分支__free_pages_ok()先对释放的页做了些检查,然后具体的释放通过调用free_one_page()-->__free_one_page()来完成 static inline void __free_one_page(struct page *page,

struct zone *zone, unsigned int order,

int migratetype)

{

unsigned long page_idx;

if (unlikely(PageCompound(page)))

if (unlikely(destroy_compound_page(page, order)))

return;

VM_BUG_ON(migratetype == -1);

/*得到页框在所处最大块中的偏移*/

page_idx = page_to_pfn(page) & ((1 << MAX_ORDER) - 1);

VM_BUG_ON(page_idx & ((1 << order) - 1));

VM_BUG_ON(bad_range(zone, page));

/*只要阶数小于MAX_ORDER-1就有合并的机会*/

while (order < MAX_ORDER-1) {

unsigned long combined_idx;

struct page *buddy;

/*找到page所处块对应的伙伴块*/

buddy = __page_find_buddy(page, page_idx, order);

/*如果伙伴块不是空闲的则不执行下面的合并操作*/

if (!page_is_buddy(page, buddy, order))

break;

/* Our buddy is free, merge with it and move up one order. */

list_del(&buddy->lru);/*将伙伴块从块链表中删除*/

zone->free_area[order].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++;/*阶数加1表明合并完成*/

}

/*重新设置块的阶数*/

set_page_order(page, order);

/*将新块添加到对应的链表中*/

list_add(&page->lru,

&zone->free_area[order].free_list[migratetype]);

zone->free_area[order].nr_free++;

}

这里面涉及到两个辅助函数,_page_find_buddy()用来找到是释放块的伙伴,如果找到了一个空闲的伙伴块要通过_find_combined_index()用来定位合并块的起始页框,因为一个块的伙伴块有可能在该块的前面,也有可能在该块的后面,这两个函数的实现非常简洁巧妙,全是通过位操作来实现的 static inline struct page *

__page_find_buddy(struct page *page, unsigned long page_idx, unsigned int order)

{

unsigned long buddy_idx = page_idx ^ (1 << order);

return page + (buddy_idx - page_idx);

}

static inline unsigned long

__find_combined_index(unsigned long page_idx, unsigned int order)

{

return (page_idx & ~(1 << order));

}

我们可以通过一个简单的情形来模拟一下这个过程,假设现在有一个将要释放的页,它的order为0,page_idx为10

则先计算它的伙伴 10^(1<<0) = 11,然后计算合并后的起始页偏移为10&~(1<<0) = 10,现在就得到了一个order为1的块,起始页偏移为10,它的伙伴为10^(1<<1)=8,合并后的起始页偏移为10&~(1<<1)=8,如此推导下去,我们可以通过下图和下表更清晰地分析这个过程

1ed005001a12c9293bc5e22c4dffd3d5.png

b778e8382be49c6fa59c2902fda7aaa4.png

其中pi代表page_idx, ci代表combined_idx

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值