基于 kernel 4.0 初始kmalloc

news2024/11/15 9:04:11

kmalloc 系列函数是驱动者常用来向内核大管家申请内存的API,今天抽空扒一扒它是怎么工作的;首先看看它的原型

1. kmalloc () 函数

static __always_inline void *kmalloc(size_t size, gfp_t flags)
{
    if (__builtin_constant_p(size)) {
        if (size > KMALLOC_MAX_CACHE_SIZE)
            return kmalloc_large(size, flags);
#ifndef CONFIG_SLOB
        if (!(flags & GFP_DMA)) {
            int index = kmalloc_index(size);

            if (!index)
                return ZERO_SIZE_PTR;

            return kmem_cache_alloc_trace(kmalloc_caches[index],
                    flags, size);
        }
#endif
    }
    return __kmalloc(size, flags);
}

代码路径:

 include/linux/slab.h

函数的返回值和参数

返回值: void*,即为分配到的内存的首地址;

参数有两个,size ---》 申请内存的大小,字节(byte)为单位, flags ---》 所需要内存的标志,其中标志定义在 include\linux\gfp.h 中,详细的介绍,其中也有注释说明,内核中常用的是 “GFP_KERNEL”,表示 该片内存是在内核内部使用的。

2. kmalloc 函数通读

(1)__builtin_constant_p(x)

===》 编译时判断x是否为常数,如果为常数,则返回1, 否则返回0

(2)宏  KMALLOC_MAX_CACHE_SIZE

===》

#define KMALLOC_MAX_CACHE_SIZE	(1UL << KMALLOC_SHIFT_HIGH)

关于 KMALLOC_SHIFT_HIGH

#ifdef CONFIG_SLAB
.........
#define KMALLOC_SHIFT_HIGH	((MAX_ORDER + PAGE_SHIFT - 1) <= 25 ? \
				(MAX_ORDER + PAGE_SHIFT - 1) : 25)
.........
#endif
#endif

#ifdef CONFIG_SLUB
.........
#define KMALLOC_SHIFT_HIGH	(PAGE_SHIFT + 1)
........
#endif
#endif

#ifdef CONFIG_SLOB
........
#define KMALLOC_SHIFT_HIGH	PAGE_SHIFT
........
#endif
#endif

定义了 CONFIG_SLUB,SLAB 和 SLOB 均未定义; 因此,使用的是宏:

#define KMALLOC_SHIFT_HIGH (PAGE_SHIFT + 1)

PAGE_SHIFT 定义如下:

arch/arm/include/asm/page.h:14:#define PAGE_SHIFT 12

arch/arm64/include/asm/page.h:24:#define PAGE_SHIFT 16

arch/arm64/include/asm/page.h:26:#define PAGE_SHIFT 1

此处是arm,因此 PAGE_SHIFT = 12, KMALLOC_SHIFT_HIGH =PAGE_SHIFT + 1 = 12 + 1 = 13, KMALLOC_MAX_CACHE_SIZE = (1 << 13 ) = 8192 bits = 8K bytes。

打印的数据和这里吻合:

按照程序逻辑,当所需的内存不大于8129 bytes(8M)的时候,调用 __kmalloc(size, flags) 进行内存分配;当所需内存大于8129 bytes(8M)的时候,调用 kmalloc_large(size, flags) 进行内存分配。 

3.  __kmalloc(size, flags)函数

根据之前的记录,这里应该是调用的mm/slub.c 中__kmalloc(),因为配置了  CONFIG_SLUB 配置项,而没有配置 CONFIG_SLAB 和 CONFIG_SLOB,因此 slob.c 和 slab.c 两个文件不会被编译。

源码:

void *__kmalloc(size_t size, gfp_t flags)
{
	struct kmem_cache *s;
	void *ret;

	if (unlikely(size > KMALLOC_MAX_CACHE_SIZE))
		return kmalloc_large(size, flags);

	s = kmalloc_slab(size, flags);

	if (unlikely(ZERO_OR_NULL_PTR(s)))
		return s;

	ret = slab_alloc(s, flags, _RET_IP_);

	trace_kmalloc(_RET_IP_, ret, size, s->size, flags);

	ret = kasan_kmalloc(s, ret, size, flags);

	return ret;
}
EXPORT_SYMBOL(__kmalloc);

这里也会判断大小,超过 8192 bits,就会调用其 kmalloc_large() 函数,未超过,则调用 kmalloc_slab() 来进行内存大小的分配;如果分配失败,则调用 slab_alloc()。

(1)kmalloc_slab()

路径:mm\slab_common.c

struct kmem_cache *kmalloc_slab(size_t size, gfp_t flags)
{
	int index;

	if (unlikely(size > KMALLOC_MAX_SIZE)) {
		WARN_ON_ONCE(!(flags & __GFP_NOWARN));
		return NULL;
	}

	if (size <= 192) {
		if (!size)
			return ZERO_SIZE_PTR;

		index = size_index[size_index_elem(size)];
	} else
		index = fls(size - 1);

#ifdef CONFIG_ZONE_DMA
	if (unlikely((flags & GFP_DMA)))
		return kmalloc_dma_caches[index];

#endif
	return kmalloc_caches[index];
}

A. 若所需要的内存大于 KMALLOC_MAX_SIZE 则 返回NULL

KMALLOC_MAX_SIZE = ?

#define KMALLOC_MAX_SIZE    (1UL << KMALLOC_SHIFT_MAX)
#define KMALLOC_SHIFT_MAX    (MAX_ORDER + PAGE_SHIFT)

如上2.(2)所述,page shift 为12, 那max order呢?

/* Free memory management - zoned buddy allocator.  */
#ifndef CONFIG_FORCE_MAX_ZONEORDER
#define MAX_ORDER 11
#else
#define MAX_ORDER CONFIG_FORCE_MAX_ZONEORDER
#endif

从上面的代码可看出,这取决于 CONFIG_FORCE_MAX_ZONEORDER 是否配置了,查看.config文件,

有该配置的定义:

CONFIG_FORCE_MAX_ZONEORDER=11,

因此 max order 定义为11,

KMALLOC_MAX_SIZE = 1<<23 = 8M,kmalloc_slab() 函数中,最大能分配的内存大小,就是不超过8M。

B. index 大小 :如果所需的内存大小不大于192,从数组size_index[] 中获取;否则,通过 fls()进行计算。

C. 分配方法 kmalloc_caches[] 数组或者 kmalloc_dma_caches[] 数组。

从 kmalloc_dma_caches[] 数组 分配内存有两个条件:配置了可以从DMA 分配内存 且 需要内存的flags 是 GFP_DMA(内存需要者,需要的就是DMA 上的内存)。

数组 kmalloc_caches[] 的来源

struct kmem_cache *kmalloc_caches[KMALLOC_SHIFT_HIGH + 1];
EXPORT_SYMBOL(kmalloc_caches);

KMALLOC_SHIFT_HIGH 大小上述已确定为13,因此 kmalloc_caches[] 指针大小为 14;

(2)若 kmalloc_slab() 函数分配内存失败,则调用slab_alloc()进行内存分配,具体的梳理,后续呈上。

(3)对于大于8M大内存的分配——kmalloc_large()函数

路径:include\linux\slab.h

源码:

static __always_inline void *kmalloc_large(size_t size, gfp_t flags)
{
    unsigned int order = get_order(size);
    return kmalloc_order_trace(size, flags, order);
}
  • get_order()
tatic inline __attribute_const__ int get_order(unsigned long size)
{
    int lz;
    asm ("nsau %0, %1" : "=r" (lz) : "r" ((size - 1) >> PAGE_SHIFT));
    return 32 - lz;
}

此处应用汇编对值进行了计算,这个汇编没太看懂。

  • kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order)
static __always_inline void *
kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order)
{
    return kmalloc_order(size, flags, order);
}
void *kmalloc_order(size_t size, gfp_t flags, unsigned int order)
{
    void *ret;
    struct page *page;

    flags |= __GFP_COMP;
    page = alloc_kmem_pages(flags, order);
    ret = page ? page_address(page) : NULL;
    kmemleak_alloc(ret, size, 1, flags);
    kasan_kmalloc_large(ret, size);
    return ret;
}
EXPORT_SYMBOL(kmalloc_order);

从以上的流程大概可以看出,超过8M的时候,是从页(page)上获取内存的,具体的细节,后续梳理梳理。

4. 遗留的问题

(1) kmalloc_caches 结构体数组的初始化

(2) slab_alloc() 内存分配的过程梳理

(3)kmalloc_order() 未入口的page内存分配过程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/934610.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

性能测试工具分享推荐

性能测试工具 常用性能测试工具性能测试工具又分为软件性能测试工具和系统性能测试工具&#xff0c;以下主要从开源免费工具和商用工具两方面进行整理&#xff0c;开源工具是免费的但通常功能有限&#xff0c;商业工具价格也不便宜&#xff0c;具体还是要结合自己的需求来选择…

AI图片鉴黄检测合规图片API

AI图片鉴黄检测合规图片API 一、AI图片鉴黄检测合规二、使用步骤1、接口2、请求参数3、请求参数示例4、接口 返回示例 三、 报错说明1、返回以下报错说明你没有正确传入检测是图片的参数(file参数), 且请求参数是**multipart/form-data**格式⚠️ 一、AI图片鉴黄检测合规 人工…

JUC——多线程补充

前置可看 Java——多线程和锁_java多线程锁_北岭山脚鼠鼠的博客-CSDN博客 线程创建的三种方式 Thread、Runnable、Callable Thread类 Runable接口 Callable接口 Lamda表达式 Lamda表达式_北岭山脚鼠鼠的博客-CSDN博客 静态代理模式(Thread类的原理) 如下代码中 真实对象…

前端vue2、vue3去掉url路由“ # ”号——nginx配置

文章目录 ⭐前言⭐vue2中router默认出现#号&#x1f496;在vue2项目中去掉&#x1f496;在vue3项目中去掉 ⭐vue打包 assetsPublicPath base 为绝对路径 /&#x1f496;vue2 配置 assetsPublicPath&#x1f496;vue3 配置 base&#x1f496;验证 ⭐nginx 配置&#x1f496; 使用…

ROS-3.ros创建工作空间和工作包

工作空间 工作空间(workspace)是存放工程开发相关文件的目录&#xff0c;目录里面包括 src &#xff1a;代码空间&#xff0c;ROS的catkin软件包&#xff08;源代码包&#xff09;build&#xff1a;编译空间&#xff0c;catkin&#xff08;CMake&#xff09;的缓存信息和中间…

关于事件回调机制

OVERVIEW 关于事件回调机制1.事件回调编程模式2.C中的事件回调编程模式函数指针回调函数对象回调 3.简单回调实例 关于事件回调机制 1.事件回调编程模式 当涉及到编程和软件开发时&#xff0c;事件回调是一种常见的编程模式。它用于处理异步事件和消息传递系统中的事件通知。 …

map set

✅<1>主页&#xff1a;我的代码爱吃辣&#x1f4c3;<2>知识讲解&#xff1a;C STL map&&set☂️<3>开发环境&#xff1a;Visual Studio 2022&#x1f4ac;<4>前言&#xff1a;map和set是C98就已经支持的两个搜索效率极高的容器&#xff0c;其底…

无涯教程-分类算法 - 随机森林

随机森林是一种监督学习算法&#xff0c;可用于分类和回归&#xff0c;但是&#xff0c;它主要用于分类问题&#xff0c;众所周知&#xff0c;森林由树木组成&#xff0c;更多树木意味着更坚固的森林。同样&#xff0c;随机森林算法在数据样本上创建决策树&#xff0c;然后从每…

高中信息技术教资考试模拟卷(22下)

2022 年下半年全国教师资格考试模考卷一 &#xff08;高中信息技术&#xff09; 一、单项选择题&#xff08;本大题共 15 小题&#xff0c;每小题 3 分&#xff0c;共 45 分&#xff09; 1.2006 年 10 月 25 日&#xff0c;深圳警方成功解救出一名被网络骗子孙某…

认识Spring AOP面向切面编程

目录 一、面向切面编程思维&#xff08;AOP&#xff09; 二、AOP思想主要的应用场景 三、AOP术语名词介绍 四、Spring AOP框架介绍和关系梳理 一、面向切面编程思维&#xff08;AOP&#xff09; AOP&#xff1a;Aspect Oriented Programming面向切面编程 AOP可以说是OOP&a…

Linux 三剑客

grep grep主打的就是查找功能 &#xff0c;它能够在一个或者多个文件中搜索某一特定的字符模式。 grep的语法 grep [选项] 模式 文件名 先说选项&#xff1a; 1.选项 要么是正则要么是字符串 -c 列出共出现多少次 -i 忽略大小写 -n 在前面列出行号 -v …

分类模型评估指标——准确率、精准率、召回率、F1、ROC曲线、AUC曲线

机器学习模型需要有量化的评估指标来评估哪些模型的效果更好。 本文将用通俗易懂的方式讲解分类问题的混淆矩阵和各种评估指标的计算公式。将要给大家介绍的评估指标有&#xff1a;准确率、精准率、召回率、F1、ROC曲线、AUC曲线。 机器学习评估指标大全 所有事情都需要评估好…

Mycat之前世今生

如果我有一个32核心的服务器&#xff0c;我就可以实现1个亿的数据分片&#xff0c;我有32核心的服务器么&#xff1f;没有&#xff0c;所以我至今无法实现1个亿的数据分片。——MyCAT ‘s Plan 话说“每一个成功的男人背后都有一个女人”&#xff0c;自然MyCAT也逃脱不了这个诅…

AI自动驾驶也“区分人种”?有色人种和儿童面临更高碰撞风险

8月27日消息&#xff0c;随着人工智能&#xff08;AI&#xff09;的快速发展&#xff0c;尤其是在自动驾驶汽车领域&#xff0c;这项技术给人类带来了巨大的便利。 然而&#xff0c;据最新的研究发现&#xff0c;自动驾驶汽车中的行人检测软件可能存在一些严重问题&#xff0c;…

章节 3:React.js基础 -《React.js手把手教程:从初学者到实战高手》- 第一部分:React.js基础

《React.js手把手教程&#xff1a;从初学者到实战高手》 第一部分&#xff1a;React.js基础 章节 3&#xff1a;React.js基础 在这一章中&#xff0c;我们将进一步了解 React.js 的基础知识。我们会从最基本的 React 组件开始&#xff0c;逐步引导你进入 React.js 的世界。 …

RocketMQ同步复制和异步复制

如果一个Broker组有Master和Slave&#xff0c;消息需要从Master复制到Slave上&#xff0c;有同步和异步两种复制方式。 1)同步复制 同步复制方式是等Master和Slave均写成功后才反馈给客户端写成功状态&#xff1b; 在同步复制方式下&#xff0c;如果Master出故障&#xff0c…

调用paddleocr接口实现文本检测与识别,并在图像中显示识别结果

目录 一、按照官网步骤安装paddlepaddle和paddleocr(paddlepaddle我安装的是cpu版本) 二、运行下面的脚本 三、图像结果 一、按照官网步骤安装paddlepaddle和paddleocr(paddlepaddle我安装的是cpu版本) doc/doc_ch/quickstart.md PaddlePaddle/PaddleOCR - Gitee.com 二、…

IDEA对Web和Tomcat的一些配置

这里只是做了自己学习中的一点记录&#xff0c;仅供参考哈&#xff01; 配置Tomcat Modules新增Web 新增module后新增Artifacts 新增Artifacts后Tomcat新增布署 将指定的module由普通java项目变成web项目 直接创建布署到Tomcat时所需要的Aritifacts包 配置Servlet的依赖包 配置…

初识【类和对象】

目录 1.面向过程和面向对象初步认识 2.类的引入 3.类的定义 4.类的访问限定符及封装 5.类的作用域 6.类的实例化 7.类的对象大小的计算 8.类成员函数的this指针 1.面向过程和面向对象初步认识 C语言是面向过程的&#xff0c;关注的是过程&#xff0c;分析出求解问题的…

Java进阶篇--创建线程的四种方式

目录 继承Thread类 扩展小知识&#xff1a; Thread类的常见方法 Thread 类的静态方法 实现Runnable接口 使用Callable和Future创建线程 使用Executor框架创建线程池 继承Thread类 创建一个继承自Thread类的子类&#xff0c;并重写其run()方法&#xff0c;将相关逻辑实现…