kmem_cache_free ---> __cache_free
limit表示的是cache中最多空闲的obj个数,如果cache中avail的数目小于 limit,那么表示可以将obj直接
放入到缓存中,等待新的分配到来。
如果cache中空闲的obj太多了,那么,需要将obj放入到slab中。当然这个返回并不是返回一个,而是将batchount个obj返回给slab。这个工作是cache_flusharray来做的。
if (likely(ac->avail < ac->limit)) {
STATS_INC_FREEHIT(cachep);
ac->entry[ac->avail++] = objp;
return;
} else {
STATS_INC_FREEMISS(cachep);
cache_flusharray(cachep, ac);
ac->entry[ac->avail++] = objp;
}
1 cache_flusharray函数
如果三链有共享的Cache,那么可以将obj移入共享cache中。
当然条件是共享的cache不能太满。条件是(shared_array->limit - shared_array->avail)>0
拷贝个数是ac->batchcount个obj
if (l3->shared) {
struct array_cache *shared_array = l3->shared;
int max = shared_array->limit - shared_array->avail;
if (max) {
if (batchcount > max)
batchcount = max;
memcpy(&(shared_array->entry[shared_array->avail]),
ac->entry, sizeof(void *) * batchcount);
shared_array->avail += batchcount;
goto free_done;
}
}
如果不能往共享cache中拷贝,那么只能往移到三链中的slab中去。这是由free_block完成的
2 free_block函数。
这个函数其实是将缓存ac中的batchcount个obj返回给slab中的三链中
对每个obj执行如下操作
for (i = 0; i < nr_objects; i++) //nr_objects 就是所说的batchcount
通过obj的指针,返回slab的地址。即virt_to_slab。步骤有2
1) obj的指针放回slab的首页。首先根据obj返回obj所在页,然后根据obj所在的页返回slab的首页。
因为他们是组合页,每个页面page的first_page 都指向slab所在的首页。
struct page *page = virt_to_head_page(obj);
2)根据slab所在的page返回slab的指针。还记得上篇博文描述 alloc的过程中有个page_set_slab函数。这个
函数是设置page和slab的关系的,函数体是page->lru.prev = (struct list_head *)slab; OK,从page返回slab的指针也非常简单,page-lru.prev就指向slab。
page_get_slab(page);
list_del(&slabp->list);
将slab从当前的链表中脱离,因为这个slab要新增一个空闲的obj,这样的话,他可能从full链表转移到 partial链表,也可能从partial链表转移到 free链表,所以,先把当前这个slab从链表中移除,后面可以看到,根据实际情况,重新链到合适的链表中去。
slab_put_obj(cachep, slabp, objp, node);
这个就是将obj放入到slab中去。这个函数比较有意思,大家可以看下,加深对slab 组织形式的理解
首先根据obj的指针可以算出obj位于slab的第几个位置。
这个不难,因为slab->s_mem 这个存储的是第一个obj的位置,
根据偏移量和每个obj的大小,就知道,当前obj是第几个obj。
slabp->free = objnr; 是把刚释放的obj放到slab的第一个obj。下一次优选选择分配这个obj。
slab_bufctl(slabp)[objnr] = slabp->free; 把之前的第一个存储到管理数组slab_bufctl中。
这样大家可以看到可用的空闲slab的组织形式:
free执行的是第一个可用的obj的index,比如 free = 5
数组slab_bufctl[5] 存储的是第二个可分配的obj的index。比如slab_bufctl[5] = 2,
第三个可分配的obj去slab_bufctl[2]去找,比如slab_bufctl[2] =7.表示index是7的obj是第三个可分配的obj。 。。。。。。。以此类推。
static void slab_put_obj(struct kmem_cache *cachep, struct slab *slabp,
void *objp, int nodeid)
{
unsigned int objnr = obj_to_index(cachep, slabp, objp);
slab_bufctl(slabp)[objnr] = slabp->free;
slabp->free = objnr;
slabp->inuse--;
}
slabp->inuse--; 当前再用的obj自减。如果当前在用的obj减到了 0,表示这个slab完全空闲了。
如果当前的slab完全空闲(slabp->inuse == 0),slab 上的所有 obj都是空闲的,
1 如果整个三链上的空闲obj太多了,释放这个slab。调用slab_destroy函数完成。
2 否则,将当前的slab 链入到l3->slabs_free。
如果slab上的还有在用的obj,即inuse > 0 ,将slab 链入到l3->slabs_partial。
3 slab_destroy 函数
这个函数的作用是 三链上的空闲obj太多,有点浪费内存,需要将当前这个slab释放掉,
把页面还给伙伴内存系统。
看else部分,对于slab 所在的(多个)页面,调用伙伴内存系统的接口kmem_freepages释放掉。
如果slab头不在slab上,调用kmem_cache_free 把slab头释放掉。
static void slab_destroy(struct kmem_cache *cachep, struct slab *slabp)
{
void *addr = slabp->s_mem - slabp->colouroff;
slab_destroy_objs(cachep, slabp);
if (unlikely(cachep->flags & SLAB_DESTROY_BY_RCU)) {
struct slab_rcu *slab_rcu;
slab_rcu = (struct slab_rcu *)slabp;
slab_rcu->cachep = cachep;
slab_rcu->addr = addr;
call_rcu(&slab_rcu->head, kmem_rcu_free);
} else {
kmem_freepages(cachep, addr);
if (OFF_SLAB(cachep))
kmem_cache_free(cachep->slabp_cache, slabp);
}
}
阅读(5114) | 评论(0) | 转发(1) |