kmem_list3链表
kmem_list3的定义如下:
273 struct kmem_list3 {
274 struct list_head slabs_partial; /* partial list first, better asm code */
275 struct list_head slabs_full;
276 struct list_head slabs_free;
277 unsigned long free_objects;
278 int free_touched;
279 unsigned long next_reap;
280 struct array_cache *shared;
281 };
1)这个链表的作用是连接slab描述符和高速缓存。
高速缓存kmem_cache_s的定义如下:
302 struct kmem_cache_s {
303 /* 1) per-cpu data, touched during every alloc/free */
304 struct array_cache *array[NR_CPUS];
305 unsigned int batchcount;
306 unsigned int limit;
307 /* 2) touched by every alloc & free from the backend */
308 struct kmem_list3 lists;
...
}
在308行,是kmem_list3类型的lists,下面分析下从buddy分配一个slab,然后怎么挂到高速缓存上的链表。
cache_grow函数的定义如下:
1780 static int cache_grow (kmem_cache_t * cachep, int flags, int nodeid)
1781 {
..
1847 /* Make slab active. */
1848 list_add_tail(&slabp->list, &(list3_data(cachep)->slabs_free));
1849 STATS_INC_GROWN(cachep);
...
list3_data的定义如下:
289 #define list3_data(cachep) \
290 (&(cachep)->lists)
就是把slab描述符的list链表挂到高速缓存的lists链表中的slabs_free链表,这样就实现了高速缓存和slab描述符的连接。通过高速缓存,再通过高速缓存lists->slab_free中找到slab。
链表策略
有3种类型的链表:
slabs_partial: 这个链表中的slab节点中object部分是空闲的。
slabs_free: 这个链表中的slab节点中object都是空闲的。
slabs_full: 这个链表中的slab节点中object没有空闲的
在从slab中选取object,提冲cache的函数定义如下:
1983 static void* cache_alloc_refill(kmem_cache_t* cachep, int flags)
1984 {
1985 int batchcount;
1986 struct kmem_list3 *l3;
1987 struct array_cache *ac;
.......
2017 while (batchcount > 0) {
2018 struct list_head *entry;
2019 struct slab *slabp;
2020 /* Get slab alloc is to come from. */
2021 entry = l3->slabs_partial.next;
2022 if (entry == &l3->slabs_partial) {
2023 l3->free_touched = 1;
2024 entry = l3->slabs_free.next;
2025 if (entry == &l3->slabs_free)
2026 goto must_grow;
2027 }
2028
....
}
说明:
1)在2021行,先从lists 中的slab_partial提取slab,然后从slab中提取object。
2)如果lists中的slab_partial链表没有slab了,则从lists中的slabs_free中提取slab,然后提取object。
2.释放object
- 把cache中array_cache的object,释放到相应的slab中,并把slab从3个链表所在的链表中删除。
- 如果释放后object后slab中的object都是空闲的,并判断3个链表中的可用oject是否大于限制值,如果是
则销毁这个slab并把内存归还给buddy系统。如果3个链表总的可用object小于等于限制值,则把这个slab挂在free链表上。 - 如果slab中部分空闲,还把这个slab挂载partial链表上。
2163 static void free_block(kmem_cache_t *cachep, void **objpp, int nr_objects)
2164 {
2165 int i;
2166
2167 check_spinlock_acquired(cachep);
......
2194 /* fixup slab chains */
2195 if (slabp->inuse == 0) {
2196 if (cachep->lists.free_objects > cachep->free_limit) {
2197 cachep->lists.free_objects -= cachep->num;
2198 slab_destroy(cachep, slabp);
2199 } else {
2200 list_add(&slabp->list,
2201 &list3_data_ptr(cachep, objp)->slabs_free);
2202 }
2203 } else {
2204 /* Unconditionally move a slab to the end of the
2205 * partial list on free - maximum time for the
2206 * other objects to be freed, too.
2207 */
2208 list_add_tail(&slabp->list,
2209 &list3_data_ptr(cachep, objp)->slabs_partial);
2210 }
2211 }
2212 }