24.slab分配器(释放对象kmem_cache_free,销毁缓存kmem_cache_destroy)
如果一个分配的对象已经不再需要,那么必须使用kmem_cache_free返回给slab分配器。图3-52给出了该函数的代码流程图。
类似于分配,根据per-CPU缓存的状态不同,有两种可选的操作流程。如果per-CPU缓存中的对象数目低于允许的限制,则在其中存储一个指向缓存中对象的指针。

mm/slab.c static inline void __cache_free(kmem_cache_t *cachep, void *objp) { ... if (likely(ac->avail < ac->limit)) { ac->entry[ac->avail++] = objp; return; } else { cache_flusharray(cachep, ac); ac->entry[ac->avail++] = objp; } }
否则,必须将一些对象(准确的数目由array_cache->batchcount给出)从缓存移回slab,从编号最低的数组元素开始:缓存的实现依据先进先出原理,这些对象在数组中已经很长时间,因此不太可能仍然驻留在CPU高速缓存中。
具体的实现委托给cache_flusharray。该函数又调用了free_block,将对象从缓存移动到原来的slab,并将剩余的对象向数组起始处移动。例如,如果缓存中有30个对象的空间,而batchcount为15,则位置0到14的对象将移回slab。剩余编号15到29的对象则在缓存中向上移动,现在占据位置0到14。
将对象从缓存移回到slab是有益的,因此仔细考察一下free_block是值得的。该函数所需的参数是缓存的kmem_cache_t实例、指向缓存中对象指针数组的指针、表示数组中对象数目的整数和内存所属的结点。
mm/slab.c static void free_block(kmem_cache_t *cachep, void **objpp, int nr_objects, int node) { int i; struct kmem_list3 *l3; for (i = 0; i < nr_objects; i++) { void *objp = objpp[i]; struct slab *slabp; ...
对每个对象必须执行下列操作:
mm/slab.c
slabp = virt_to_slab(objp);
l3 = cachep->nodelists[node];
list_del(&slabp->list);
slab_put_obj(cachep, slabp, objp, node);
slabp->inuse--;
l3->free_objects++;
在确定对象所属的slab之前,首先必须调用virt_to_page找到对象所在的页。与slab之间的关联使用前文所述的page_get_slab确定。
该slab(临时)从缓存的链表移除。slab_put_obj反映了在空闲链表中的这种操作:用于分配的第一个对象是刚刚删除的,而列表中的下一个对象则是此前的第一个对象。此后,该slab重新插入到缓存的链表中:
mm/slab.c ... /* 修正slab所处的链表 */ if (slabp->inuse == 0) { if (l3->free_objects > l3->free_limit) { l3->free_objects -= cachep->num; slab_destroy(cachep, slabp); } else { list_add(&slabp->list, &l3->slabs_free); } } else { list_add(&slabp->list, &l3->slabs_partial); } } }
如果在删除之后,slab中的所有对象都是未使用的(slab->inuse == 0),则将slab置于slabs_free链表中。
例外情况:缓存中空闲对象的数目超过预定义的限制cachep->free_limit。在这种情况下,使用slab_destroy将整个slab返回给伙伴系统。
如果slab同时包含使用和未使用对象,则插入到slabs_partial链表
销毁缓存
如果要销毁只包含未使用对象的一个缓存,则必须调用kmem_cache_destroy函数。该函数主要在删除模块时调用,此时需要将分配的内存都释放。由于该函数的实现没什么新东西,下面我们只是概述一下删除缓存的主要步骤。
依次扫描slabs_free链表上的slab。首先对每个slab上的每个对象调用析构器函数,然后将slab的内存空间返回给伙伴系统。
释放用于per-CPU缓存的内存空间。
从cache_cache链表移除相关数据。
浙公网安备 33010602011771号