Chinaunix首页 | 论坛 | 博客
  • 博客访问: 47007
  • 博文数量: 14
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 35
  • 用 户 组: 普通用户
  • 注册时间: 2018-11-19 18:25
文章分类

全部博文(14)

文章存档

2018年(14)

我的朋友

分类: LINUX

2018-11-19 19:45:46

我们的分析顺序是初始化、创建cache、申请对象、申请对象时会涉及创建slab、释放对象、释放对象时会涉及释放slab、销毁cache。
前面已经介绍到了创建slab,本节分析一下释放对象,有两个入口kfree和kmem_cache_free,由于两者实现的本质相同只是对外体现为了两个API,
这里放在一起梳理一下,下面分析一下代码。

点击(此处)折叠或打开

  1. /**
  2.  * kfree - free previously allocated memory
  3.  * @objp: pointer returned by kmalloc.
  4.  *
  5.  * If @objp is NULL, no operation is performed.
  6.  *
  7.  * Don't free memory not originally allocated by kmalloc()
  8.  * or you will run into trouble.
  9.  */
  10. void kfree(const void *objp)
  11. {
  12.     struct kmem_cache *c;
  13.     unsigned long flags;

  14.     trace_kfree(_RET_IP_, objp);

  15.     /* 检查需要释放的对象地址是否有效 */
  16.     if (unlikely(ZERO_OR_NULL_PTR(objp)))
  17.         return;
  18.     local_irq_save(flags);
  19.     kfree_debugcheck(objp);
  20.     /* 首先根据对象地址获取其所在的page,然后page的lru->prev指向了slab,page的lru->next指向了cache */
  21.     /* 在前文中介绍申请slab的cache_grow函数中调用的slab_map_pages完成了Page和cache/slab的映射关系 */
  22.     c = virt_to_cache(objp);
  23.     debug_check_no_locks_freed(objp, obj_size(c));
  24.     debug_check_no_obj_freed(objp, obj_size(c));
  25.     /* 找到了释放对象所属的cache,下面函数进行释放 */
  26.     __cache_free(c, (void *)objp);
  27.     local_irq_restore(flags);
  28. }

点击(此处)折叠或打开

  1. /*
  2.  * Release an obj back to its cache. If the obj has a constructed state, it must
  3.  * be in this state _before_ it is released. Called with disabled ints.
  4.  */
  5. static inline void __cache_free(struct kmem_cache *cachep, void *objp)
  6. {
  7.     /* 获取当前cache中的local cache,即cachep->array[smp_processor_id()] */
  8.     struct array_cache *ac = cpu_cache_get(cachep);

  9.     check_irq_off();
  10.     kmemleak_free_recursive(objp, cachep->flags);
  11.     objp = cache_free_debugcheck(cachep, objp, __builtin_return_address(0));

  12.     kmemcheck_slab_free(cachep, objp, obj_size(cachep));

  13.     /*
  14.      * Skip calling cache_free_alien() when the platform is not numa.
  15.      * This will avoid cache misses that happen while accessing slabp (which
  16.      * is per page memory reference) to get nodeid. Instead use a global
  17.      * variable to skip the call, which is mostly likely to be present in
  18.      * the cache.
  19.      */
  20.     /* 判断当前是否为NUMA架构,对于NUMA架构需要判断释放的对象所在的内核节点与当前CPU所属的内存节点是否相同 */
  21.     /* 如果相同,则执行后续的释放操作;如果不同在cache_free_alien函数中完成释放,并在下面return */
  22.     /* 假设当前为UMA架构,先继续往下分析,cache_free_alien留在后面分析 */
  23.     if (nr_online_nodes > 1 && cache_free_alien(cachep, objp))
  24.         return;
  25.     /* 判断当前local cache中的可用对象数量是否超过了上限 */
  26.     if (likely(ac->avail < ac->limit)) {
  27.         /* 未超上限 */
  28.         /* 增加释放的命中计数 */
  29.         STATS_INC_FREEHIT(cachep);
  30.         /* 将释放对象直接保存在local cache中,申请时取[--ac->avail]释放时是[ac->avail++],可以看出每次申请的都是最近释放的对象 */
  31.         ac->entry[ac->avail++] = objp;
  32.         return;
  33.     } else {
  34.         /* 已超出上限 */
  35.         /* 增加释放未命中的计数 */
  36.         STATS_INC_FREEMISS(cachep);
  37.         /* 由于local cache中对象数量太多,需要释放batch_count个对象出去,后面我们会分析cache_flusharray函数 */
  38.         cache_flusharray(cachep, ac);
  39.         /* local cache中已经释放了一批,已有新空间记录最近释放的对象 */
  40.         ac->entry[ac->avail++] = objp;
  41.     }
  42. }

点击(此处)折叠或打开

  1. static void cache_flusharray(struct kmem_cache *cachep, struct array_cache *ac)
  2. {
  3.     int batchcount;
  4.     struct kmem_list3 *l3;
  5.     /* 根据当前cpu获取所在的内存节点ID */
  6.     int node = numa_node_id();
  7.     /* 每次申请和释放,需要批量处理的对象个数 */
  8.     batchcount = ac->batchcount;
  9. #if DEBUG
  10.     BUG_ON(!batchcount || batchcount > ac->avail);
  11. #endif
  12.     check_irq_off();
  13.     /* 获取当前cache的slab 三链,kmem_list3结构  */
  14.     l3 = cachep->nodelists[node];
  15.     spin_lock(&l3->list_lock);
  16.     /* 如果有shared 的local cache */
  17.     if (l3->shared) {
  18.         struct array_cache *shared_array = l3->shared;
  19.         /* 计算当前shared local cache还能容纳多少slab对象,limit是上限,avail是当前拥有的空闲数量 */
  20.         int max = shared_array->limit - shared_array->avail;
  21.         if (max) {
  22.             /* 不能超过shared local cache的容纳上限 */
  23.             if (batchcount > max)
  24.                 batchcount = max;
  25.             /* Entry数组中记录的都是可用对象的地址,直接批量拷贝过去即可 */
  26.             memcpy(&(shared_array->entry[shared_array->avail]),
  27.              ac->entry, sizeof(void *) * batchcount);
  28.             /* 更新shared local cache当前的可用对象数量 */
  29.             shared_array->avail += batchcount;
  30.             goto free_done;
  31.         }
  32.     }
  33.     /* 没有shared cache或者shared cache已经放满了,无法融入更多的对象,此时需要释放到slab三链中 */
  34.     free_block(cachep, ac->entry, batchcount, node);
  35. free_done:
  36. #if STATS
  37.     {
  38.         int i = 0;
  39.         struct list_head *p;

  40.         p = l3->slabs_free.next;
  41.         while (p != &(l3->slabs_free)) {
  42.             struct slab *slabp;

  43.             slabp = list_entry(p, struct slab, list);
  44.             BUG_ON(slabp->inuse);

  45.             i++;
  46.             p = p->next;
  47.         }
  48.         STATS_SET_FREEABLE(cachep, i);
  49.     }
  50. #endif
  51.     spin_unlock(&l3->list_lock);
  52.     /* 至此,已批量释放batchcount个对象,调整avail的值 */
  53.     ac->avail -= batchcount;
  54.     /* 由于先释放的是旧的对象,即数组前面的对象,所以需要后面的对象整体前移 */
  55.     memmove(ac->entry, &(ac->entry[batchcount]), sizeof(void *)*ac->avail);
  56. }

点击(此处)折叠或打开

  1. /*
  2.  * Caller needs to acquire correct kmem_list's list_lock
  3.  */
  4. /* 没有shared cache,或者shared cache已经满载的情况下,会调用该函数进行回收
  5.    cachep: 需要回收对象的cache
  6.    objpp: local cache中记录slab对象的数组首地址 
  7.    nr_objects: 需要释放的slab对象的数量
  8.    node: 当前cpu所在的NUMA节点,也是当前slab对象所属的NUMA节点*/
  9. static void free_block(struct kmem_cache *cachep, void **objpp, int nr_objects,
  10.          int node)
  11. {
  12.     int i;
  13.     struct kmem_list3 *l3;
  14.     /* 遍历需要释放的对象 */
  15.     for (i = 0; i < nr_objects; i++) {
  16.         /* 根据索引,获取需要释放的对象 */
  17.         void *objp = objpp[i];
  18.         struct slab *slabp;
  19.         /* 根据slan对象获取其所属的slab,首先根据对象地址获取其所在page,根据page->lru.prev可以获取slab */
  20.         slabp = virt_to_slab(objp);
  21.         /* 根据NUMA节点获取slab三链 */
  22.         l3 = cachep->nodelists[node];
  23.         /* 将slab从原有链表上摘除,现在在那个链表上(free/paritcal/full三链之一) */
  24.         list_del(&slabp->list);
  25.         check_spinlock_acquired_node(cachep, node);
  26.         check_slabp(cachep, slabp);
  27.         /* 将对象释放到slab中 */
  28.         /* 更新slab->inuse计数,更新slab->free指向当前释放的对象索引,更新slab->bufctl(slabp)[当前对象索引]指向上一节点索引 */
  29.         slab_put_obj(cachep, slabp, objp, node);
  30.         /* 减少当前cache中活跃对象的数量 */
  31.         STATS_DEC_ACTIVE(cachep);
  32.         /* 增加slab三链中可用空闲对象的计数 */
  33.         l3->free_objects++;
  34.         check_slabp(cachep, slabp);

  35.         /* fixup slab chains */
  36.         /* 判断当前slab是否已经没有正在使用的对象 */
  37.         if (slabp->inuse == 0) {
  38.             /* 当前slab三链中空闲对象数量已经超过了上限 */
  39.             if (l3->free_objects > l3->free_limit) {
  40.                 /* 此时需要销毁一个slab,而每个slab中含有cache->num个对象,所以先把free_objects更新了,然后销毁slab */
  41.                 l3->free_objects -= cachep->num;
  42.                 /* No need to drop any previously held
  43.                  * lock here, even if we have a off-slab slab
  44.                  * descriptor it is guaranteed to come from
  45.                  * a different cache, refer to comments before
  46.                  * alloc_slabmgmt.
  47.                  */
  48.                 /* 销毁一个slab,见后文单独篇幅分析 */
  49.                 slab_destroy(cachep, slabp);
  50.             } else {
  51.                 /* 由于slab的所有对象已空闲,将slab挂在free链表上 */
  52.                 list_add(&slabp->list, &l3->slabs_free);
  53.             }
  54.         } else {
  55.             /* Unconditionally move a slab to the end of the
  56.              * partial list on free - maximum time for the
  57.              * other objects to be freed, too.
  58.              */
  59.             /* 将slab挂在到partical链表上 */
  60.             list_add_tail(&slabp->list, &l3->slabs_partial);
  61.         }
  62.     }
  63. }
阅读(2152) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~