




已阅读5页,还剩6页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
slab源码分析-销毁函数释放对象注意释放对象仅仅是回收回slab,并不会将内存还给伙伴系统。回收对象时有以下原则:本地高速缓存的空间还可以容纳空闲对象,则直接将对象放回本地高速缓存。本地高速缓存的空间已满,则按batchcount的值将对象从本地高速缓存转移到本地共享缓存shared中,如果没有设置本地共享缓存,那么就转移到slab三链中。转移时基于先进先出原则的,也就是转移entry数组最前面的batchcount个空闲对象,因为这些对象在数组中存在的时间相对较长,为“冷数据”,不大可能仍然驻留在CPU高速缓存中。释放对象比如调用: /底层调用_cache_free()函数 _cache_free(cachep, objp);那么释放对象就正式开始了,首先是_cache_free()函数,在该函数中首先确定ac有没有超过上限,如果没有超过上限,那就把该对象放入ac即可。否则,就按照batchcount转移出ac一大批对象,为这一个对象腾地方(一大批为一个,这样效率高一些,免得以后再转移)。/* * Release an obj back to its cache. If the obj has a constructed state, it must * be in this state _before_ it is released. Called with disabled ints. */ /回收函数static inline void _cache_free(struct kmem_cache *cachep, void *objp) /获得本CPU的本地缓存 struct array_cache *ac = cpu_cache_get(cachep); check_irq_off(); objp = cache_free_debugcheck(cachep, objp, _builtin_return_address(0); /NUMA相关,目前版本是空函数 if (cache_free_alien(cachep, objp) return; /下面开始选择释放位置进行释放 /本地缓存中的空闲对象小于上限时,只需将对象释放回entry数组中 if (likely(ac-avail limit) STATS_INC_FREEHIT(cachep); ac-entryac-avail+ = objp; return; else /这是本地缓存空闲对象大于上限的情况,先调整本地缓存 STATS_INC_FREEMISS(cachep); cache_flusharray(cachep, ac); /不过之后还是要把该对象释放给本地缓存 ac-entryac-avail+ = objp; 再看cache_flusharray()函数:static void cache_flusharray(struct kmem_cache *cachep, struct array_cache *ac) int batchcount; struct kmem_list3 *l3; int node = numa_node_id(); /本地缓存能一次转出多少个对象,这个是之前规定的 batchcount = ac-batchcount;#if DEBUG BUG_ON(!batchcount | batchcount ac-avail);#endif check_irq_off(); /获得此缓存器的三链 l3 = cachep-nodelistsnode; spin_lock(&l3-list_lock); /看是否存在本地共享缓存 if (l3-shared) struct array_cache *shared_array = l3-shared; /本地 共享 缓存还可承载的最大数目 int max = shared_array-limit - shared_array-avail; if (max) /最大只能为max if (batchcount max) batchcount = max; /将本地缓存前面的几个对象转入本地共享缓存中,因为前面的是最早不用的 memcpy(&(shared_array-entryshared_array-avail), ac-entry, sizeof(void *) * batchcount); /更新本地共享缓存 shared_array-avail += batchcount; goto free_done; /没有配置本地共享缓存,只能释放对象到三链中 /注意此时的 batchcount 就是原始的 batchcount,也就是说可以把达到本地缓存一次性转出 batchcount 的目标 /而上面的本地共享缓存如果使用的话,有可能达不到这个目标,因为它也有 limit /不过即便达不到,由于本地共享缓存效率比三链高,这种情况也不会在到三链来,而是直接goto free_done。 free_block(cachep, ac-entry, batchcount, node);free_done:#if STATS /.DEBUG#endif spin_unlock(&l3-list_lock); /更新本地缓存的情况 ac-avail -= batchcount; /把后面的移动到本地缓存数组前面来 memmove(ac-entry, &(ac-entrybatchcount), sizeof(void *)*ac-avail);如果没有本地共享缓存,或者本地共享缓存达到limit了,那就把该对象回收到三链中:/* * Caller needs to acquire correct kmem_lists list_lock */ /释放一定数目的对象static void free_block(struct kmem_cache *cachep, void *objpp, int nr_objects, int node) int i; struct kmem_list3 *l3; /逐一释放对象到三链中 for (i = 0; i nodelistsnode; /先将对象所在的slab从链表中摘除 list_del(&slabp-list); check_spinlock_acquired_node(cachep, node); check_slabp(cachep, slabp); /将对象放到其 slab 中 slab_put_obj(cachep, slabp, objp, node); STATS_DEC_ACTIVE(cachep); /增加空闲对象计数 l3-free_objects+; check_slabp(cachep, slabp); /* fixup slab chains */ /如果slab中全都是空闲对象 if (slabp-inuse = 0) /如果三链中空闲对象数目超过上限,直接回收整个 slab 到内存,空闲对象数减去每个slab中对象数 if (l3-free_objects l3-free_limit) l3-free_objects -= cachep-num; /* No need to drop any previously held * lock here, even if we have a off-slab slab * descriptor it is guaranteed to come from * a different cache, refer to comments before * alloc_slabmgmt. */ /销毁slab对象 slab_destroy(cachep, slabp); else /到这里说明空闲对象数目还没有超过三链设置的上限 /只需将此slab添加到空slab链表中 list_add(&slabp-list, &l3-slabs_free); else /* Unconditionally move a slab to the end of the * partial list on free - maximum time for the * other objects to be freed, too. */ /将此slab添加到部分满的链表中 list_add_tail(&slabp-list, &l3-slabs_partial); 整个流程就是这样,回收优先级:本地缓存本地共享缓存三链。 销毁slab销毁slab就是释放slab管理区和对象占用的空间,还给伙伴系统。* * slab_destroy - destroy and release all objects in a slab * cachep: cache pointer being destroyed * slabp: slab pointer being destroyed * * Destroy all the objs in a slab, and release the mem back to the system. * Before calling the slab must have been unlinked from the cache. The * cache-lock is not held/needed. */ /销毁slab,需要释放管理对象和slab对象static void slab_destroy(struct kmem_cache *cachep, struct slab *slabp) /获得slab页面的首地址,是用第一个对象的地址colouroff(对于内置式slab,colouroff已经将slab管理者包括在内了) void *addr = slabp-s_mem - slabp-colouroff; /debug用 slab_destroy_objs(cachep, slabp); /使用SLAB_DESTROY_BY_RCU来创建的高速缓存 if (unlikely(cachep-flags & SLAB_DESTROY_BY_RCU) /rcu方式释放,暂时不做分析,主要是做并行优化 struct slab_rcu *slab_rcu; slab_rcu = (struct slab_rcu *)slabp; slab_rcu-cachep = cachep; slab_rcu-addr = addr; /注册一个回调来延期释放slab call_rcu(&slab_rcu-head, kmem_rcu_free); else /释放slab占用的页面到伙伴系统中 /如果是内置式,slab管理者和slab对象在一起,可以同时释放 kmem_freepages(cachep, addr); if (OFF_SLAB(cachep) /外置式,还需释放slab管理对象 kmem_cache_free(cachep-slabp_cache, slabp); 与伙伴系统交互的函数暂不再本文讨论范围之内。 销毁缓存器销毁缓存器首先要保证的一点就是当前缓存器中所有的对象都是空闲的,也就是之前分配出去的对象都已经释放回来了,其主要的步骤如下:将缓存器 kmem_cache 从 cache_chain 链表中删除。将本地高速缓存,align高速缓存和本地共享缓存中的对象都回收到slab三链,并释放所有的free链表,然后判断full链表以及partial链表是否都为空,如果有一个不为空说明存在非空闲slab,也就是说*还有对象未释放,此时无法销毁缓存器,必须重新将缓存器添加到 cache_chain 链表中。确定所有的对象都为空闲状态后,将缓存器涉及到的所有描述符都释放(这些描述符都是保存在通用缓存器中的,如slab管理者)。负责销毁缓存器的函数为kmem_cache_destroy():/* * kmem_cache_destroy - delete a cache * cachep: the cache to destroy * * Remove a &struct kmem_cache object from the slab cache. * * It is expected this function will be called by a module when it is * unloaded. This will remove the cache completely, and avoid a duplicate * cache being allocated each time a module is loaded and unloaded, if the * module doesnt have persistent in-kernel storage across loads and unloads. * * The cache must be empty before calling this function. * * The caller must guarantee that noone will allocate memory from the cache * during the kmem_cache_destroy(). */ /销毁一个缓存器,通常这只发生在卸载module时void kmem_cache_destroy(struct kmem_cache *cachep) BUG_ON(!cachep | in_interrupt(); /* Find the cache in the chain of caches. */ mutex_lock(&cache_chain_mutex); /* * the chain is never empty, cache_cache is never destroyed */ /将缓存器从cache_chain的链表中摘除 list_del(&cachep-next); if (_cache_shrink(cachep) /释放空链表中的slab,并检查其他两个链表。在销毁缓存器前,必须先销毁其中的slab /满slab链或部分满slab链不为空 slab_error(cachep, Cant free all objects); /缓存器非空,不能销毁,重新加入到cache_chain链表中 list_add(&cachep-next, &cache_chain); mutex_unlock(&cache_chain_mutex); return; /有关rcu if (unlikely(cachep-flags & SLAB_DESTROY_BY_RCU) synchronize_rcu(); /底层调用_kmem_cache_destroy()函数来实现 _kmem_cache_destroy(cachep); mutex_unlock(&cache_chain_mutex);释放空链表的slab由下面这个函数负责:/* Called with cache_chain_mutex held to protect against cpu hotplug */释放空链表中的slabstatic int _cache_shrink(struct kmem_cache *cachep) int ret = 0, i = 0; struct kmem_list3 *l3; /释放本地缓存中对象 drain_cpu_caches(cachep); check_irq_on(); for_each_online_node(i) l3 = cachep-nodelistsi; if (!l3) continue; /释放空链表中的slab drain_freelist(cachep, l3, l3-free_objects); /检查满slab链表和部分满slab链表是否还有slab ret += !list_empty(&l3-slabs_full) | !list_empty(&l3-slabs_partial); return (ret ? 1 : 0);其中用到了这几个函数:/释放本地缓存和本地共享缓存中的对象static void drain_cpu_caches(struct kmem_cache *cachep) struct kmem_list3 *l3; int node; /释放每个本地缓存中的对象,注意没有 online on_each_cpu(do_drain, cachep, 1, 1); /调用了do_drain()函数 check_irq_on(); /NUMA相关,释放每个NUMA节点的alien for_each_online_node(node) l3 = cachep-nodelistsnode; if (l3 & l3-alien) /本版本目前是空函数,暂不支持 drain_alien_cache(cachep, l3-alien); /释放本地共享缓存中的对象 for_each_online_node(node) l3 = cachep-nodelistsnode; if (l3) drain_array(cachep, l3, l3-shared, 1, node); /释放本地缓存中的对象static void do_drain(void *arg) struct kmem_cache *cachep = arg; struct array_cache *ac; int node = numa_node_id(); check_irq_off(); /获得本地缓存 ac = cpu_cache_get(cachep); spin_lock(&cachep-nodelistsnode-list_lock); /释放本地缓存中的对象 free_block(cachep, ac-entry, ac-avail, node); spin_unlock(&cachep-nodelistsnode-list_lock); ac-avail = 0;/* * Drain an array if it contains any elements taking the l3 lock only if * necessary. Note that the l3 listlock also protects the array_cache * if drain_array() is sed on the shared array. */void drain_array(struct kmem_cache *cachep, struct kmem_list3 *l3, struct array_cache *ac, int force, int node) int tofree; if (!ac | !ac-avail) return; if (ac-touched & !force) ac-touched = 0; else spin_lock_irq(&l3-list_lock); if (ac-avail) /计算释放对象的数目,可见这个函数还支持部分释放,取决于force的bool属性 /从 drain_cpu_caches()进入时,force=1,是要全部释放的 tofree = force ? ac-avail : (ac-limit + 4) / 5; if (tofree ac-avail) tofree = (ac-avail + 1) / 2; /释放对象,从entry前面开始 free_block(cachep, ac-entry, tofree, node); ac-avail -= tofree; /后面的对象前移 memmove(ac-entry, &(ac-entrytofree), sizeof(void *) * ac-avail); spin_unlock_irq(&l3-list_lock); drain_array()函数是把本地缓存和本地共享缓存释放到三链中,所以会用到:/* * Caller needs to acquire correct kmem_lists list_lock */ /释放一定数目的对象static void free_block(struct kmem_cache *cachep, void *objpp, int nr_objects, int node) int i; struct kmem_list3 *l3; /逐一释放对象到三链中 for (i = 0; i nodelistsnode; /先将对象所在的slab从链表中摘除 list_del(&slabp-list); check_spinlock_acquired_node(cachep, node); check_slabp(cachep, slabp); /将对象放到其 slab 中 slab_put_obj(cachep, slabp, objp, node); STATS_DEC_ACTIVE(cachep); /增加空闲对象计数 l3-free_objects+; check_slabp(cachep, slabp); /* fixup slab chains */ /如果slab中全都是空闲对象 if (slabp-inuse = 0) /如果三链中空闲对象数目超过上限,直接回收整个 slab 到内存,空闲对象数减去每个slab中对象数 if (l3-free_objects l3-free_limit) l3-free_objects -= cachep-num; /* No need to drop any previously held * lock here, even if we have a off-slab slab * descriptor it is guaranteed to come from * a different cache, refer to comments before * alloc_slabmgmt. */ /销毁slab对象 slab_destroy(ca
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 【正版授权】 ISO 6877:2025 EN Dentistry - Endodontic obturating materials
- 【正版授权】 ISO 22504:2025 EN Oil and gas industries including lower carbon energy - Pipeline transportation systems - Onshore and offshore pipelines pig traps design requirements
- 液温考试试题及答案
- 莆田哲理考试题及答案
- 机车制动试题及答案
- 校园安全知识培训课件图片
- 神经阻滞考试题及答案
- 安永税务面试题及答案
- 高一语文期末考试题及答案
- 押运员实体考试试题及答案
- GB/T 45411.1-2025光学和光子学瞄准望远镜规范第1部分:普通性能仪器
- 外销出口流程培训
- 房屋建筑工程竣工验收技术资料统一用表(2024 版)
- 《企业研发费用税前加计扣除政策解读与应用课件》
- 《马斯克英文介绍》课件
- OptiStruct结构分析与工程应用
- GA/T 1280-2024银行自助设备安全性规范
- 带状疱疹后神经痛的诊治课件
- 火灾地震逃生演练课件
- 广东省深圳市2024-2025学年高一上学期期中考试数学试卷(含答案)
- 第6讲立体几何(2022-2023年高考真题)(原卷版)
评论
0/150
提交评论