Linux Slab分配器(七)--銷燬緩存

水平有限,描述不當之處還請之處,轉載請註明出處http://blog.csdn.net/vanbreaker/article/details/7674601

銷燬緩存首先要保證的一點就是緩存當中所有的對象都是空閒的,也就是之前分配出去的對象都已經釋放回來了,其主要的步驟如下

1.將緩存從cache_chain鏈表中刪除

2.將本地高速緩存、alien高速緩存和共享本地高速緩存中的對象都釋放回slab並釋放所有的free鏈表,然後判斷full鏈表以及partial鏈表是否都爲空,如果有一個不爲空說明存在非空閒slab,也就是說有對象還未釋放,此時無法銷燬緩存,重新將緩存添加到cache_chain鏈表中

3.確定所有的slab都爲空閒狀態後,將緩存涉及到的所有描述符都釋放(這些描述符都是保存在普通高速緩存中的)

 

負責銷燬緩存的函數爲kmem_cache_destroy()

void kmem_cache_destroy(struct kmem_cache *cachep)
{
	BUG_ON(!cachep || in_interrupt());

	/* Find the cache in the chain of caches. */
	get_online_cpus();
	mutex_lock(&cache_chain_mutex);
	/*
	 * the chain is never empty, cache_cache is never destroyed
	 */
	/*將cache從cache_chain中刪除*/
	list_del(&cachep->next);
	
	/*釋放完free鏈表,如果FULL鏈表或partial鏈表中還有slab,說明還有對象處於分配狀態
	因此不能銷燬該緩存!*/
	if (__cache_shrink(cachep)) {
		slab_error(cachep, "Can't free all objects");
		/*重新將緩存添加到cache_chain鏈表中*/
		list_add(&cachep->next, &cache_chain);
		mutex_unlock(&cache_chain_mutex);
		put_online_cpus();
		return;
	}

	if (unlikely(cachep->flags & SLAB_DESTROY_BY_RCU))
		rcu_barrier();

	/*釋放cache所涉及到的各個描述符的存儲對象*/
	__kmem_cache_destroy(cachep);
	mutex_unlock(&cache_chain_mutex);
	put_online_cpus();
}


 

static int __cache_shrink(struct kmem_cache *cachep)
{
	int ret = 0, i = 0;
	struct kmem_list3 *l3;

	/*將本地高速緩存,share本地高速緩存以及alien高速緩存的空閒對象釋放slab*/
	drain_cpu_caches(cachep);

	check_irq_on();
	for_each_online_node(i) {
		l3 = cachep->nodelists[i];
		if (!l3)
			continue;
                  /*銷燬空閒鏈表中的slab*/
		drain_freelist(cachep, l3, l3->free_objects);

		/*判斷full和partial是否爲空,有一個不爲空則ret就爲1*/
		ret += !list_empty(&l3->slabs_full) ||
			!list_empty(&l3->slabs_partial);
	}
	return (ret ? 1 : 0);
}

drain_cpu_caches()的最終落腳在free_block()函數上,該函數在前面已做過分析,在此不再列出

 

static int drain_freelist(struct kmem_cache *cache,
			struct kmem_list3 *l3, int tofree)
{
	struct list_head *p;
	int nr_freed;
	struct slab *slabp;

	nr_freed = 0;
	/*slab中的對象還未釋放完並且free鏈表不爲空*/
	while (nr_freed < tofree && !list_empty(&l3->slabs_free)) {

		spin_lock_irq(&l3->list_lock);
		p = l3->slabs_free.prev;
		if (p == &l3->slabs_free) {/*鏈表中已無元素*/
			spin_unlock_irq(&l3->list_lock);
			goto out;
		}
		/*從free鏈表中取出一個slab*/
		slabp = list_entry(p, struct slab, list);
#if DEBUG
		BUG_ON(slabp->inuse);
#endif
		/*從鏈表中刪除*/
		list_del(&slabp->list);
		/*
		 * Safe to drop the lock. The slab is no longer linked
		 * to the cache.
		 */
		 /*空閒對象數量總數減去num*/
		l3->free_objects -= cache->num;
		spin_unlock_irq(&l3->list_lock);
		/*銷燬slab*/
		slab_destroy(cache, slabp);
		nr_freed++;
	}
out:
	return nr_freed;
}

slab_destroy()函數已在前文中分析

 

static void __kmem_cache_destroy(struct kmem_cache *cachep)
{
	int i;
	struct kmem_list3 *l3;

	/*釋放存儲本地高速緩存描述符的對象*/
	for_each_online_cpu(i)
	    kfree(cachep->array[i]);

	/* NUMA: free the list3 structures */
	for_each_online_node(i) {
		l3 = cachep->nodelists[i];
		if (l3) {
			/*釋放存儲共享本地高速緩存描述符的對象*/
			kfree(l3->shared);
			/*釋放存儲alien本地高速緩存描述符的對象*/
			free_alien_cache(l3->alien);
			/*釋放存儲kmem_list3描述符的對象*/
			kfree(l3);
		}
	}
	/*釋放存儲緩存描述符的對象*/
	kmem_cache_free(&cache_cache, cachep);
}


 


發佈了59 篇原創文章 · 獲贊 33 · 訪問量 50萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章