您的位置:首页 > 运维架构 > Linux

linux 3.4.10 内核内存管理源代码分析9:Slab内存释放

2013-06-09 20:17 344 查看

法律声明:《linux
3.4.10 内核内存管理源代码分析》系列文章由机器人(ancjf@163.com)发表于http://blog.csdn.net/ancjf,文章遵循GPL协议。欢迎转载,转载请注明作者和此条款。



Slab内存释放======================

kmem_cache_free函数

向一个slab中释放内存的的函数是kmem_cache_free,在mm/slab.c中实现,代码如下:

3914 void kmem_cache_free(struct kmem_cache*cachep, void *objp)

3915 {

3916 unsigned long flags;

3917

3918 local_irq_save(flags);

3919 debug_check_no_locks_freed(objp, obj_size(cachep));

3920 if (!(cachep->flags & SLAB_DEBUG_OBJECTS))

3921 debug_check_no_obj_freed(objp,obj_size(cachep));

3922 __cache_free(cachep, objp, __builtin_return_address(0));

3923 local_irq_restore(flags);

3924

3925 trace_kmem_cache_free(_RET_IP_, objp);

3926 }

除了开关中断和一些调试代码,释放的主要工作是调用__cache_free函数实现的。

__cache_free函数

释放也分两种情况,如果一个cpu对象缓存的对象数目达到了上限,slab系统会对cup对象缓存进行刷新,就是把对象归还给slab块,如果这样造成的slab空闲对象数也超过限制,则会把空闲slab块也释放回伙伴系统。__cache_free在mm/slab.c中实现,代码如下:

3670 static void cache_flusharray(structkmem_cache *cachep, struct array_cache *ac)

3671 {

3672 int batchcount;

3673 struct kmem_list3 *l3;

3674 int node = numa_mem_id();

3675

3676 batchcount = ac->batchcount;

3677 #if DEBUG

3678 BUG_ON(!batchcount || batchcount > ac->avail);

3679 #endif

3680 check_irq_off();

3681 l3 = cachep->nodelists[node];

3682 spin_lock(&l3->list_lock);

3683 if (l3->shared) {

3684 struct array_cache*shared_array = l3->shared;

3685 int max =shared_array->limit - shared_array->avail;

3686 if (max) {

3687 if (batchcount >max)

3688 batchcount =max;

3689 memcpy(&(shared_array->entry[shared_array->avail]),

3690 ac->entry, sizeof(void *) *batchcount);

3691 shared_array->avail+= batchcount;

3692 goto free_done;

3693 }

3694 }

3695

3696 free_block(cachep, ac->entry, batchcount, node);

3697 free_done:

3698 #if STATS

3699 {

3700 int i = 0;

3701 struct list_head *p;

3702

3703 p = l3->slabs_free.next;

3704 while (p !=&(l3->slabs_free)) {

3705 struct slab *slabp;

3706

3707 slabp = list_entry(p,struct slab, list);

3708 BUG_ON(slabp->inuse);

3709

3710 i++;

3711 p = p->next;

3712 }

3713 STATS_SET_FREEABLE(cachep, i);

3714 }

3715 #endif

3716 spin_unlock(&l3->list_lock);

3717 ac->avail -= batchcount;

3718 memmove(ac->entry, &(ac->entry[batchcount]), sizeof(void*)*ac->avail);

3719 }

不考虑宏DEBUG和宏STATS中的代码,cache_flusharray函数就分成两种情况,一种是本节点的三链表存在共享slab对象缓存的情况,这样情况会把slab对象移动到三链表中的共享的slab对象缓存中,否则会调用free_block函数清理slab对象缓存中的队列。

3683-3694行是三链表执行的共享slab缓存对象不为空的情况,这中情况会把slab对象缓存中超过限制的对象移动到共享的slab缓存对象中。3685行求出共享的slab对象缓存还能存放多少个对象,如果还能往里面放入对象就执行3687-3692行代码,把一些对象移动到共享slab对象缓存中。

3696调用free_block函数释放对象。

3717行减少可用对象计数

3718行因为前面的对象已经被移动到共享的slab对象缓存或释放给对象所属的slab块了,但后面还有对象是可用的,所以要把后面对象的指针前移。

free_block函数

真正把对象释放回slab块是在free_block中完成的,free_block在mm/slab.c中实现,代码如下:

3626 static void free_block(struct kmem_cache*cachep, void **objpp, int nr_objects,

3627 int node)

3628 {

3629 int i;

3630 struct kmem_list3 *l3;

3631

3632 for (i = 0; i < nr_objects; i++) {

3633 void *objp = objpp[i];

3634 struct slab *slabp;

3635

3636 slabp = virt_to_slab(objp);

3637 l3 =cachep->nodelists[node];

3638 list_del(&slabp->list);

3639 check_spinlock_acquired_node(cachep, node);

3640 check_slabp(cachep,slabp);

3641 slab_put_obj(cachep, slabp,objp, node);

3642 STATS_DEC_ACTIVE(cachep);

3643 l3->free_objects++;

3644 check_slabp(cachep, slabp);

3645

3646 /* fixup slab chains*/

3647 if (slabp->inuse == 0) {

3648 if(l3->free_objects > l3->free_limit) {

3649 l3->free_objects -= cachep->num;

3650 /* No need to drop any previously held

3651 * lock here,even if we have a off-slab slab

3652 * descriptorit is guaranteed to come from

3653 * a differentcache, refer to comments before

3654 *alloc_slabmgmt.

3655 */

3656 slab_destroy(cachep, slabp);

3657 } else {

3658 list_add(&slabp->list,&l3->slabs_free);

3659 }

3660 } else {

3661 /* Unconditionallymove a slab to the end of the

3662 * partial list onfree - maximum time for the

3663 * other objects to befreed, too.

3664 */

3665 list_add_tail(&slabp->list, &l3->slabs_partial);

3666 }

3667 }

3668 }

free_block的代码其实也比较简单,下面分析几行关键代码。

3636行调用virt_to_slab获得struct slab的地址,我们知道根据虚拟地址可以获得管理该虚拟你在的struct page结构地址,而structslab地址存储了struct page的成员lru.prev中。3641行调用slab_put_obj函数把对象归还给salb块。

3638行把slab块从原来的链表删除,因为向该slab块归还了一个对象,该slab块可能已经成为完全空闲块,3647根据slab块是否有对象正在使用中来把slab块加入不同的队列,3649-3659是slab块完全空闲的情况。如果slab块完全空闲,还要考虑一种情况就是空闲slab块的数目是不是超过了限制,3649-3656属于这种情况,3649减少空闲对象计数,3656调用slab_destroy块释放一块slab块。对于空闲块数量没有超过限制的情况,3658把slab块加入三链表的完全空闲队列。对还不是完全空闲的slab块,3665行吧slab块加入部分空闲链表。

slab_destroy函数

slab_destroy用于销毁slab块,就是把slab块释放到伙伴系统,在mm/slab.c中实现,代码如下:

2085 static void slab_destroy(structkmem_cache *cachep, struct slab *slabp)

2086 {

2087 void *addr = slabp->s_mem - slabp->colouroff;

2088

2089 slab_destroy_debugcheck(cachep, slabp);

2090 if (unlikely(cachep->flags & SLAB_DESTROY_BY_RCU)) {

2091 struct slab_rcu *slab_rcu;

2092

2093 slab_rcu = (struct slab_rcu*)slabp;

2094 slab_rcu->cachep = cachep;

2095 slab_rcu->addr = addr;

2096 call_rcu(&slab_rcu->head,kmem_rcu_free);

2097 } else {

2098 kmem_freepages(cachep, addr);

2099 if (OFF_SLAB(cachep))

2100 kmem_cache_free(cachep->slabp_cache, slabp);

2101 }

2102 }

在函数alloc_slabmgmt计算struct slab的存放地址是用2798行代码: slabp->s_mem = objp + colour_off,现在计算slab块的首地址就是slabp->s_mem -slabp->colouroff。

不考虑使用rcu的情况,剩下的代码就是2098行调用kmem_freepages释放slab的内存,2099-2100如果struct slab是单独存放的,也需要释放这部分空间,这部分空间是属于slab的,调用kmem_cache_free释放。

kmem_freepages函数

kmem_freepages在mm/slab.c中实现,代码如下:

1837 static void kmem_freepages(structkmem_cache *cachep, void *addr)

1838 {

1839 unsigned long i = (1 << cachep->gfporder);

1840 struct page *page = virt_to_page(addr);

1841 const unsigned long nr_freed = i;

1842

1843 kmemcheck_free_shadow(page, cachep->gfporder);

1844

1845 if (cachep->flags & SLAB_RECLAIM_ACCOUNT)

1846 sub_zone_page_state(page_zone(page),

1847 NR_SLAB_RECLAIMABLE,nr_freed);

1848 else

1849 sub_zone_page_state(page_zone(page),

1850 NR_SLAB_UNRECLAIMABLE, nr_freed);

1851 while (i--) {

1852 BUG_ON(!PageSlab(page));

1853 __ClearPageSlab(page);

1854 page++;

1855 }

1856 if (current->reclaim_state)

1857 current->reclaim_state->reclaimed_slab += nr_freed;

1858 free_pages((unsigned long)addr, cachep->gfporder);

1859 }

kmem_freepages函数调用free_pages释放slab块的空间到伙伴系统,free_pages需要两个参数:地址和slab块的阶,slab块的阶存放在struct kmem_cache的成员gfporder中。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐