内存管理 初始化(七)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 > ) limit = ;
| else if (cachep->buffer_size > PAGE_SIZE) limit = ;
| else if (cachep->buffer_size > ) limit = ;
| else if (cachep->buffer_size > ) limit = ;
| else limit = ;
| 为什么选择这些数值啊,不明白???
|
|-->int shared = ;
| if(cachep->buffer_size <= PAGE_SIZE && num_possible_cpus() > )
| shared = ;
|
|--int err = ;
| err = do_tune_cpucache(cachep, limit, (limit + ) / , 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, );
| 将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 = ;
| 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 = ( + NR_CPUS) * cachep->batchcount
| | + cachep->num;| | kfree(shared);
| | free_alien_cache(new_alien);
| | continue; //对于单节点,再次continue时,将退出循环
| |-}
| |
| |
| ...... 对于UMA体系 nothing
| |
|--}
|
|--return ;
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 = ;
| nc->limit = entries;
| nc->batchcount = batchcount;
| nc->touched = ;
| spin_lock_init(&nc->lock);
|
|-->return nc;
内存管理 初始化(七)kmem_cache_init_late 初始化slab分配器(下)的更多相关文章
- Linux内存管理6---伙伴算法与slab
1.前言 本文所述关于内存管理的系列文章主要是对陈莉君老师所讲述的内存管理知识讲座的整理. 本讲座主要分三个主题展开对内存管理进行讲解:内存管理的硬件基础.虚拟地址空间的管理.物理地址空间的管理. 本 ...
- DPDK内存管理-----(一)初始化
1 前言 DPDK通过使用hugetlbfs,减少CPU TLB表的Miss次数,提高性能. 2 初始化 DPDK的内存初始化工作,主要是将hugetlbfs的配置的大内存页,根据其映射的物理地址是否 ...
- 启动期间的内存管理之bootmem_init初始化内存管理–Linux内存管理(十二)
1. 启动过程中的内存初始化 首先我们来看看start_kernel是如何初始化系统的, start_kerne定义在init/main.c?v=4.7, line 479 其代码很复杂, 我们只截取 ...
- 启动期间的内存管理之初始化过程概述----Linux内存管理(九)
在内存管理的上下文中, 初始化(initialization)可以有多种含义. 在许多CPU上, 必须显式设置适用于Linux内核的内存模型. 例如在x86_32上需要切换到保护模式, 然后内核才能检 ...
- Linux内存管理 - slab分配器和kmalloc
本文目的在于分析Linux内存管理机制的slab分配器.内核版本为2.6.31.1. SLAB分配器 内核需要经常分配内存,我们在内核中最常用的分配内存的方式就是kmalloc了.前面讲过的伙伴系统只 ...
- 内存管理之slab分配器
基本思想 与传统的内存管理模式相比, slab 缓存分配器提供了很多优点.首先,内核通常依赖于对小对象的分配,它们会在系统生命周期内进行无数次分配.slab 缓存分配器通过对类似大小的对象进行缓存而提 ...
- Linux内存管理之bootmem分配器
为什么要使用bootmem分配器,内存管理不是有buddy系统和slab分配器吗?由于在系统初始化的时候需要执行一些内存管理,内存分配的任务,这个时候buddy系统,slab分配器等并没有被初始化好, ...
- 启动期间的内存管理之引导分配器bootmem--Linux内存管理(十)
在内存管理的上下文中, 初始化(initialization)可以有多种含义. 在许多CPU上, 必须显式设置适用于Linux内核的内存模型. 例如在x86_32上需要切换到保护模式, 然后内核才能检 ...
- (笔记)Linux内核学习(九)之内核内存管理方式
一 页 内核把物理页作为内存管理的基本单位:内存管理单元(MMU)把虚拟地址转换为物理 地址,通常以页为单位进行处理.MMU以页大小为单位来管理系统中的也表. 32位系统:页大小4KB 64位系统:页 ...
随机推荐
- 3. 支持向量机(SVM)拉格朗日对偶性(KKT)
1. 感知机原理(Perceptron) 2. 感知机(Perceptron)基本形式和对偶形式实现 3. 支持向量机(SVM)拉格朗日对偶性(KKT) 4. 支持向量机(SVM)原理 5. 支持向量 ...
- struts学习笔记
------struts in action 读书笔记 1. ActionServlet:Struts 的ActionServlet控制导航流.当ActionServlet从容器接到一个请求,它使用U ...
- wamp安装xdebug特殊情况win7 64位安装32位wamp
在wamp上安装xdebug网上很多文章都介绍了方法,但是我这里遇到了一个很特殊的情况,在网上很少有人提及: 我机器是win7 64位的,安装的wamp1.7.4是32位的,这是后来导致出现奇怪现象的 ...
- java基础篇---JSP内置对象详解
在JSP中为了简化用户的开发,提供了九个内置对象,这些内置对象将由容器为用户进行实例化,而用户直接使用即可,而不用像在java中那样,必须通过关键字new进行实例化对象之后才可以使用. No. 内 ...
- Java实现图片添加水印
参考别人的感觉挺好玩,还没仔细研究,先上代码. package WaterMark; import javax.imageio.ImageIO; import java.awt.*; import j ...
- C语言 · 新生舞会
算法训练 新生舞会 时间限制:1.0s 内存限制:512.0MB 问题描述 新生舞会开始了.n名新生每人有三个属性:姓名.学号.性别.其中,姓名用长度不超过20的仅由大小写字母构成的 ...
- [加密]展讯secureboot方案
Secure Boot方案介绍及实施流程 转自网络 1. Secure boot概述 本文档主要是secure boot方案的介绍和说明,其内容会涵盖以下方面:secure boot的目的和介绍.技术 ...
- Java多线程编程中Future模式的详解<转>
Java多线程编程中,常用的多线程设计模式包括:Future模式.Master-Worker模式.Guarded Suspeionsion模式.不变模式和生产者-消费者模式等.这篇文章主要讲述Futu ...
- Maven MyEclipse创建web项目没有src/maim/java
转载:http://blog.csdn.net/nich002/article/details/43273219 maven项目 错误: 找不到或无法加载主类 分类: java2015-01-29 ...
- windows10删除开始菜单中的xbox、人脉、邮件等应用
1.右键单击PowerShell,选择“以管理员身份运行” 2.输入下面的命令回车,会列出系统中所有已安装应用列表. Get-AppxPackage -AllUsers 从列表中找到你要卸载的应用,并 ...