linux vi 内存,Vi Linux内存 之 Slub分配器(四)

本文详细介绍了Linux内核中如何使用kmem_cache_free函数将对象返回给slub分配器。slab_free函数首先获取对象所在的slab首页,然后根据对象是否在本CPU的局部slab中,选择快速或慢速路径进行释放。在慢速路径中,对象被放回slab的free链表,并可能涉及调整部分满slab链表。整个过程涉及到slab的冻结状态检查、对象计数和slab状态的更新。
摘要由CSDN通过智能技术生成

本节介绍如何将对象释放回slub分配器。

kmem_cache_free

void kmem_cache_free(struct kmem_cache *s, void *x)

{

struct page *page;

/*获得对象所在slab的首页*/

page = virt_to_head_page(x);

/*释放一个对象给slab。_RET_IP_为调用函数地址*/

slab_free(s, page, x, _RET_IP_);

trace_kmem_cache_free(_RET_IP_, x);

}

slab_free

释放一个对象。

参数:

1)s:cache指针。

2)page:待释放对象所在slab的首页。

3)x:待释放对象指针

4)addr:最初调用函数的地址

static __always_inline void slab_free(struct kmem_cache *s,

struct page *page, void *x, unsigned long addr)

{

void **object = (void *)x;

struct kmem_cache_cpu *c;

unsigned long flags;

slab_free_hook(s, x);

local_irq_save(flags);

c = __this_cpu_ptr(s->cpu_slab);

slab_free_hook_irq(s, x);

if (likely(page == c->page && c->node != NUMA_NO_NODE)) {

/*如果对象所在slab即本cpu local slab,走快速路径,释放到cpu freelist中。与slab的freelist无关,参见__slab_alloc */

set_freepointer(s, object, c->freelist);

/*更新freelist指针,指向刚释放的对象*/

c->freelist = object;

stat(s, FREE_FASTPATH);

} else

/*慢速路径释放*/

__slab_free(s, page, x, addr);

local_irq_restore(flags);

}

__slab_free

待释放对象所在slab并不是本cpu的local slab时,走慢速路径释放,

static void __slab_free(struct kmem_cache *s, struct page *page,

void *x, unsigned long addr)

{

void *prior;

void **object = (void *)x;

stat(s, FREE_SLOWPATH);

slab_lock(page);

if (kmem_cache_debug(s))

goto debug;

checks_ok:

/*放回所在slab freelist的链表头部*/

prior = page->freelist;

/*待释放对象的下一对象指针指向原freelist */

set_freepointer(s, object, prior);

/* freelist指向待释放的对象*/

page->freelist = object;

/*已分配对象数减一*/

page->inuse--;

/* slab是否是冻结的。该slab有可能是其他cpu的local slab,这种情况下,不能执行后面的语句将local slab添加进部分满slab链*/

if (unlikely(PageSlubFrozen(page))) {

stat(s, FREE_FROZEN);

goto out_unlock;

}

/* inuse为0,又不是local slab,说明slab中全部是空闲对象,并且在部分满slab链表上(slab只有一个对象时,在满slab链上)。*/

if (unlikely(!page->inuse))

goto slab_empty;

/*

* Objects left in the slab. If it was not on the partial list before

* then add it.

*/

/*如果slab原本是满slab,现在释放了一个,加入部分满slab链*/

if (unlikely(!prior)) {

add_partial(get_node(s, page_to_nid(page)), page, 1);

stat(s, FREE_ADD_PARTIAL);

}

out_unlock:

slab_unlock(page);

return;

slab_empty:

if (prior) {

/*

* Slab still on the partial list.

*/

/* prior不为空时,说明slab在部分满slab链表上。prior为空时,说明slab只有一个对象,在满slab链上*/

remove_partial(s, page);

stat(s, FREE_REMOVE_PARTIAL);

}

slab_unlock(page);

stat(s, FREE_SLAB);

/*废除slab,slub没有空slab链,slab一旦为空,马上销毁。(这点与去解冻slab时不同,参见unfreeze_slab)*/

discard_slab(s, page);

return;

debug:

if (!free_debug_processing(s, page, x, addr))

goto out_unlock;

goto checks_ok;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值