[内核内存] slab分配器3---kmem_cache_init函数源码详解

2024-05-25 09:48

本文主要是介绍[内核内存] slab分配器3---kmem_cache_init函数源码详解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

kmem_cache_init函数源码详解

//mm/slab.c
/** Initialisation.  Called after the page allocator have been initialised and* before smp_init().*slab系统初始化时伙伴系统已经初始化,但在多处理器系统上,启动CPU此时正在运行, 而其他CPU尚未初始化.*/
void __init kmem_cache_init(void)
{int i;BUILD_BUG_ON(sizeof(((struct page *)NULL)->lru) <sizeof(struct rcu_head));/**(1)kmem_cache_boot为编译时创建的静态数据,使用时不用内存分配,用作slab系统的第一个slab cache,为其它所有*   的struct kmem_cache结构分配obj.*(2)kmem_cache是一个全局的静态变量struct kmem_cache *kmem_cache*(3)将编译时创建的静态数据变量kmem_cache_boot的地址赋值给全局静态变量kmem_cache*/kmem_cache = &kmem_cache_boot;if (!IS_ENABLED(CONFIG_NUMA) || num_possible_nodes() == 1)use_alien_caches = 0;/**初始化静态定义的kmem_cache_node数组成员*	a.NUM_INIT_LISTS = 2 * MAX_NUMNODES,可以看出给每个node静态定义了两个kmem_cache_node变量,why?*  b.实际上init_kmem_cache_node是为slab系统初始化过程中前两个struct kmem_cache实例的node成员提供存储空间,*    因为这两个实例初始化时,slab系统还未启动完全,因此仍然只能用静态变量的形式给他们的node成员提供存储空间*	  (1)第一个stcruct kmem_cache实例,就是函数开始时进行赋值操作的全局静态变量kmem_cache,该实例给其他*       stcrut kmem_cache结构的创建提供内存空间(字节计数的小块内存)*	  (2)第二个struct kmem_cache实例是创建struct kmem_cache_node结构的slab cache描述符,该实例就是给stuct*		 kmem_cache_node结构数据提供小块内存。 *ps:全局静态变量kmem_cache使用时虽然不用分配内存,但是它的node成员只是一个地址指针,它指向的区域还没有分配*内存空间,此时slab系统仍然未初始化完全,所以仍然只能用静态变量预定义的方式,来为kmem_cache的node成员指向的*区域分配空间。*/for (i = 0; i < NUM_INIT_LISTS; i++)kmem_cache_node_init(&init_kmem_cache_node[i]);/** Fragmentation resistance on low memory - only use bigger* page orders on machines with more than 32MB of memory if* not overridden on the command line.*/if (!slab_max_order_set && totalram_pages > (32 << 20) >> PAGE_SHIFT)slab_max_order = SLAB_MAX_ORDER_HI;/* Bootstrap is tricky, because several objects are allocated* from caches that do not exist yet:* 1) initialize the kmem_cache cache: it contains the struct*    kmem_cache structures of all caches, except kmem_cache itself:*    kmem_cache is statically allocated.*    Initially an __init data area is used for the head array and the*    kmem_cache_node structures, it's replaced with a kmalloc allocated*    array at the end of the bootstrap.* 2) Create the first kmalloc cache.*    The struct kmem_cache for the new cache is allocated normally.*    An __init data area is used for the head array.* 3) Create the remaining kmalloc caches, with minimally sized*    head arrays.* 4) Replace the __init data head arrays for kmem_cache and the first*    kmalloc cache with kmalloc allocated arrays.* 5) Replace the __init data for kmem_cache_node for kmem_cache and*    the other cache's with kmalloc allocated memory.* 6) Resize the head arrays of the kmalloc caches to their final sizes.*//* 1) create the kmem_cache *//** struct kmem_cache size depends on nr_node_ids & nr_cpu_ids*初始化 boot kmem_cache:主要是给第一个slab cache的各个成员赋值:*	(a)kmem_cache->node:指向init_kmem_cache_node的前一半空间.*  (b)kmem_cache->cpu_cache:通过__alloc_percpu函数来给该Per_CPU变量分配存储空间(分配array_cache实例).*	   这时启动cpu正在运行,其他cpu还未初始化。这个时候只是按照固定大小给每个cpu分配一个本地高速缓存,且不会*	   给kmem_cache->node数组成员的每个节点的分配共享cpu高速缓存,即是kmem_cache->shared=0.后面待所有cpu都*     初始化完全后,会调用kmem_cache_init_late函数完善cache_chain链表上所有struct kmem_cache实例的cpu本*     地高速缓存和其每个节点共享cpu缓存的实现。*  (c)函数的第3个参数表示的是kmem_cache中每个slab obj的大小,SLAB_HWCACHE_ALIGN要求按硬件的cache line对*     齐(一个或多个slab obj按硬件的cache line对齐)*/create_boot_cache(kmem_cache, "kmem_cache",offsetof(struct kmem_cache, node) +nr_node_ids * sizeof(struct kmem_cache_node *),SLAB_HWCACHE_ALIGN);//boot kmem_cache初始化完后,将其加入到slab_caches全局链表中.list_add(&kmem_cache->list, &slab_caches);//slab_state全局的enum类型,表示slab系统初始化当前处于哪个状态状态slab_state = PARTIAL;/*2)-4)步骤执行* Initialize the caches that provide memory for the  kmem_cache_node* structures first.  Without this, further allocations will bug.*创建第二个slab cache描述符,并将该描述符存储在kmalloc_caches全局数组中:*  (a)kmalloc_caches是一个全局变量(struct kmem_cache *kmalloc_caches[KMALLOC_SHIFT_HIGH + 1]),数组中*     存储的是通用slab cache描述符(struct kemem_cache实例).kmalloc函数分配内存的时候,会根据所需要分配的*     空间的大小,计算出一个索引值,然后利用索引值在kmalloc_caches数组中找到对应的kmem_cache实例,用该实例来*     分配slab obj.*  (b)kmalloc_size:(1)中讲到会根据kmalloc函数参数中分配内存的大小(size)获取到其对应slab cache描述符在*     kmalloc_caches数组中的索引index,这我们可以利用文档后面的kmalloc_index函数来获取:*						 index = kmalloc_index(size)*		而kmalloc_size函数是利用index来获得size:*						 size  = kmalloc_size(index) *  (c)#define INDEX_NODE kmalloc_index(sizeof(struct kmem_cache_node))* 由上面的信息可以看出,此处就是创建一个struct kmem_cache_node结构体对应的slab cache描述符,然后将该slab * cache描述符存储在通用slab cache描述符数组kmalloc_caches的INDEX_NODE索引处(INDEX_NODE根据struct * kmem_cache_node结构体的大小获取)。* ps:1.该函数结束后全局数组kmalloc_caches只有INDEX_NODE索引出由数据,其他位置仍然未赋值。*	  2.kmalloc_caches[INDEX_NODE]对应的slab cache描述符除了再全局数组中,还会添加到slab_caches链表中.*    3.第二个slab cache描述(kmalloc_caches[INDEX_NODE]),它的node成员指向的区域是init_kmem_cache_node*		数组的后半部分,也是静态定义的数据区*/kmalloc_caches[INDEX_NODE] = create_kmalloc_cache("kmalloc-node",kmalloc_size(INDEX_NODE), ARCH_KMALLOC_FLAGS);//kmalloc size for node struct available,该状态下kmalloc函数能为struct kmem_cache_node结构体分配内存了slab_state = PARTIAL_NODE;setup_kmalloc_cache_index_table();slab_early_init = 0;/* 5) Replace the bootstrap kmem_cache_node *//**此时slab_state = PARTIAL_NODE,也就是slab系统中的kmalloc能够动态地为struct kmem_cache_node结构分*配内存了.下面代码块的工作是将slab系统初始化时最先创建的两个slab cache描述符实例中的node指向的静态数据区替*换成kmalloc动态分配内存区.* (a)对于kmem_cache: 用kmalloc函数动态地为每个节点分配一个struct kmem_cache_node,然后将kmem_cache->node*    指向的静态数据区中的内容按节点先后顺序拷贝到新分配struct kmem_cache_node中,最后将kmem_cache->node指*    向新分配struct kmem_cache_node的地址处* (b)对于kmalloc_caches[INDEX_NODE]:处理方式同上.*替换的原因貌似是静态定义的__initdata在某个时刻会被自动释放。*/{int nid;for_each_online_node(nid) {init_list(kmem_cache, &init_kmem_cache_node[CACHE_CACHE + nid], nid);init_list(kmalloc_caches[INDEX_NODE],&init_kmem_cache_node[SIZE_NODE + nid], nid);}}/**(1)丰富kmalloc_caches全局数组中通用slab cache描述符的类型,[0,PAGE_SHIFT)区间内每个元素都为其分配一个对应*   的slab cache描述符,并指向它.这样更多不同大小的内存块分配需求都能很快通过kmalloc函数来满足.比如:*   kmalloc_caches[1]对应的slab cache描述符能满足0-8字节内的所有内存分配需求,kmalloc_caches[2]能满足8-16*   字节内的所有内存分配依次类推.....*(2)这样能提高slab系统kmalloc函数内存分配速度:因为各种大小区间的slab cache描述已经换成在全局数组中,*   kmalloc分配内存时不需临时分配slab cache描述符。另外这些slab cache描述符中还缓存了很多未释放到伙伴系统*   中的同等大小的内存块对象(slab obj),甚至有些slab obj还在本地cpu高速缓存中。*/*/create_kmalloc_caches(ARCH_KMALLOC_FLAGS);
}

这篇关于[内核内存] slab分配器3---kmem_cache_init函数源码详解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1001158

相关文章

PHP轻松处理千万行数据的方法详解

《PHP轻松处理千万行数据的方法详解》说到处理大数据集,PHP通常不是第一个想到的语言,但如果你曾经需要处理数百万行数据而不让服务器崩溃或内存耗尽,你就会知道PHP用对了工具有多强大,下面小编就... 目录问题的本质php 中的数据流处理:为什么必不可少生成器:内存高效的迭代方式流量控制:避免系统过载一次性

MySQL的JDBC编程详解

《MySQL的JDBC编程详解》:本文主要介绍MySQL的JDBC编程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言一、前置知识1. 引入依赖2. 认识 url二、JDBC 操作流程1. JDBC 的写操作2. JDBC 的读操作总结前言本文介绍了mysq

Redis 的 SUBSCRIBE命令详解

《Redis的SUBSCRIBE命令详解》Redis的SUBSCRIBE命令用于订阅一个或多个频道,以便接收发送到这些频道的消息,本文给大家介绍Redis的SUBSCRIBE命令,感兴趣的朋友跟随... 目录基本语法工作原理示例消息格式相关命令python 示例Redis 的 SUBSCRIBE 命令用于订

使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解

《使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解》本文详细介绍了如何使用Python通过ncmdump工具批量将.ncm音频转换为.mp3的步骤,包括安装、配置ffmpeg环... 目录1. 前言2. 安装 ncmdump3. 实现 .ncm 转 .mp34. 执行过程5. 执行结

Python中 try / except / else / finally 异常处理方法详解

《Python中try/except/else/finally异常处理方法详解》:本文主要介绍Python中try/except/else/finally异常处理方法的相关资料,涵... 目录1. 基本结构2. 各部分的作用tryexceptelsefinally3. 执行流程总结4. 常见用法(1)多个e

C++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法

SpringBoot日志级别与日志分组详解

《SpringBoot日志级别与日志分组详解》文章介绍了日志级别(ALL至OFF)及其作用,说明SpringBoot默认日志级别为INFO,可通过application.properties调整全局或... 目录日志级别1、级别内容2、调整日志级别调整默认日志级别调整指定类的日志级别项目开发过程中,利用日志

Java中的抽象类与abstract 关键字使用详解

《Java中的抽象类与abstract关键字使用详解》:本文主要介绍Java中的抽象类与abstract关键字使用详解,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录一、抽象类的概念二、使用 abstract2.1 修饰类 => 抽象类2.2 修饰方法 => 抽象方法,没有

MySQL8 密码强度评估与配置详解

《MySQL8密码强度评估与配置详解》MySQL8默认启用密码强度插件,实施MEDIUM策略(长度8、含数字/字母/特殊字符),支持动态调整与配置文件设置,推荐使用STRONG策略并定期更新密码以提... 目录一、mysql 8 密码强度评估机制1.核心插件:validate_password2.密码策略级

从入门到精通详解Python虚拟环境完全指南

《从入门到精通详解Python虚拟环境完全指南》Python虚拟环境是一个独立的Python运行环境,它允许你为不同的项目创建隔离的Python环境,下面小编就来和大家详细介绍一下吧... 目录什么是python虚拟环境一、使用venv创建和管理虚拟环境1.1 创建虚拟环境1.2 激活虚拟环境1.3 验证虚