欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

内存管理 初始化(七)kmem_cache_init_late 初始化slab分配器(下)

发布时间:2025/7/14 编程问答 55 豆豆
生活随笔 收集整理的这篇文章主要介绍了 内存管理 初始化(七)kmem_cache_init_late 初始化slab分配器(下) 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

我们知道kmem_cache中对于每CPU都有一个array_cache,已作为每CPU申请内存的缓存.  此函数的目的在于:每个kmem_cache都有一个kmem_list3实例,该实例的shared作为一个kmem_cache上所有CPU的内存申请缓存.  但是在此之前,seup_cpu_cache中对于kmem_cache中array_cache的值初始化体现不出缓存思想,而且对于kmem_cache中的kmem_list3.shared也没有利用.

kmem_cache_init_late的目的就在于完善slab分配器的缓存机制.                                                                              

start_kernel()
|-->page_address_init()||-->setup_arch(&command_line);||-->setup_per_cpu_areas();||-->build_all_zonelist()||-->page_alloc_init()||-->pidhash_init()||-->vfs_caches_init_early()||-->mm_init()||-->.......||-->gfp_allowed_mask = __GFP_BITS_MASK;| 在此之前,gfp_allowed_mask = GFP_BOOT_MASK;||-->kmem_cache_init_late();|

 

 

void __init kmem_cache_init_late(void)|-->struct kmem_cache *cachep;||-->list_for_each_entry(cachep, &cache_chain, next)|-->if (enable_cpucache(cachep, GFP_NOWAIT)) BUG();||--g_cpucache_up = FULL;||-->init_lock_keys();||-->register_cpu_notifiler(&cpu_notifier);

 

 

int enabel_cpucache(struct kmem_cache *cachep, gfp_t gfp)|-->int limit;||-->if (cachep->buffer_size > 131072) limit = 1;| else if (cachep->buffer_size > PAGE_SIZE) limit = 8;| else if (cachep->buffer_size > 1024) limit = 24;| else if (cachep->buffer_size > 256) limit = 54;| else limit = 120;| 为什么选择这些数值啊,不明白???||-->int shared = 0;| if(cachep->buffer_size <= PAGE_SIZE && num_possible_cpus() > 1)| shared = 8;||--int err = 0;| err = do_tune_cpucache(cachep, limit, (limit + 1) / 2, shared, gfp);||--return err;

 

 

int do_tune_cpucache(struct kmem_cache *cachep, int limit,int batchcount, int shared, gfp_t gfp)|-->struct ccupdate_struct *new = NULL;| new = kazlloc(sizeof(*new), gfp);||--int i;|--for_each_online_cpu(i)|--{| new->new[i] = alloc_arraycache(cpu_to_node(i), limit,
| batchcount, gfp);
| 根据limit, batchcount数值,构建新的array_cache实例.|| 因为kmem_cache中的array_cache是每个CPU的,所以此处是循环,为每个CPU都| 都构建一个array_cache实例.|--}||-->new->cachep = cachep;||-->on_each_cpu(do_ccupdate_local, (void*)new, 1);| 将kmem_cache下的每个CPU的array_cache[i]更换成new->new[i];||-->cachep->batchcount = batchcount;| cachep->limit = limit;| cachep->shared = shared;||| 上面以替换了kmem_cache下的每个CPU的array_cache[i],
| 因此需要把原来的array_cache释放掉.
|--for_each_online_cpu(i)|--{| struct array_cache *ccolde = new->new[i];| if(!ccold) continue;|| free_block(cachep, ccold->entry, ccold->avail, cpu_to_node(i));| 我们知道在此之前,ccold->avail一直为0,所以该函数暂时可以不看.| 此函数,就是把ccold->avail个ccole->entry中的数组元素指向的内存空间| 释放给slab管理器.||| kfree(ccold);| 基本同于free_block,我们知道slab所管理的内存都是位于低端内存,低端内存的物| 理地址及其对应的虚拟地址存在固定偏移,因此根据该部分的虚拟地址可以很容易的找到| struct page实例,而struct page中的lru链表,在slab中被复用了,根据链表| 指针可以找到kmem_cache实例,所以kfree基本等同于free_block;| 但是kfree与free_block的重要的不同点在于,free_block直接将内存释放给了| slab管理器,而kfree首选将内存释放给每CPU的array_cache数组.||--}|-->kfree(new);||--return alloc_kmemlist(cachep, gfp);| 每个kmem_cache中的kmem_list3.shared上array_cache可以被所有CPU共享.

 

 

我们知道kmem_cache中对于每CPU都有一个array_cache,已作为每CPU申请内存的缓存. 此函数的目的在于:每个kmem_cache都有一个kmem_list3实例,该实例的shared作为 一个kmem_cache上所有CPU的内存申请缓存(对于UMA,kmem_cache.alien没有用处). 此时,我们不妨猜测,当一个CPU通过kmalloc申请内内存时,将从kmem_cache实例上 自己的array_cache进行申请,如果没有则从kmem_list3->shared上补充到array_cache上, 如果kmem_list3上也每有,将从slab管理器上获取,充分体现了缓存的利用. int alloc_kmemlist(struct kmem_cache *cachep, gfp_t gfp)|-->int node = 0;| struct kmem_list3 *l3 = NULL;| struct array_cache *new_shared = NULL;| struct array_cache **new_alien = NULL;||-->for_each_online_node(node)|--{| new_shared = NULL;| if(cachep->shared)| new_shared = alloc_arraycache(node, | cachep->shared * cachep->batchcount,| 0xbaadf00d, gfp);||| l3 = cachep->nodelists[node];| if(l3)| |-{| | struct array_cache *shared = l3->shared;| | if(shared)
| | free_block(cachep, shared->entry, shared->avail, node);| | l3->shared = new_shared;| | if(!l3->alien) l3->alien = new_alien, new_alien = NULL;| | l3->free_limit = (1 + NR_CPUS) * cachep->batchcount
| | + cachep->num;| | kfree(shared);| | free_alien_cache(new_alien);| | continue; //对于单节点,再次continue时,将退出循环| |-}| || || ...... 对于UMA体系 nothing| |
|--}
||--return 0;

 

 

void do_ccupdate_local(void *info)|-->struct ccupdate_struct *new = info;| struct array_cache *old = cpu_cache_get(new->cachep);||-->new->cachep->array[smp_processor_id()] =
| new->new[smp_processor_id];
| new->new[smp_processor_id()] = old;

 

 

struct array_cache *alloc_arraycache(int node, int entries,int batchcount, gfp_t gfp)|-->int memsize = sizeof(void *) * entries
| + sizeof(struct array_cache);
| 根据entries的数值,计算该分配的array_cache空间大小.||-->struct array_cache *nc = NULL;| nc = kmalloc_node(memsize, gfp, node);| nc->avail = 0;| nc->limit = entries;| nc->batchcount = batchcount;| nc->touched = 0;| spin_lock_init(&nc->lock);||-->return nc;

 

《新程序员》:云原生和全面数字化实践50位技术专家共同创作,文字、视频、音频交互阅读

总结

以上是生活随笔为你收集整理的内存管理 初始化(七)kmem_cache_init_late 初始化slab分配器(下)的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。