基于 kernel 4.0 初始kmalloc

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_SLOBif (!(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 12arch/arm64/include/asm/page.h:24:#define PAGE_SHIFT 16arch/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)];} elseindex = fls(size - 1);#ifdef CONFIG_ZONE_DMAif (unlikely((flags & GFP_DMA)))return kmalloc_dma_caches[index];#endifreturn 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.mzph.cn/news/54622.shtml

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

相关文章

openssl 加密(encrypt)、解密(decrypt)、签名(sign)、验证(verify)

一、使用openssl rsautl 进行加密、解密、签名、验证 [kyzjjyyzc-zjjcs04 openssl]$ openssl rsautl --help Usage: rsautl [options] -in file input file -out file output file -inkey file input key -keyform arg private key format - default PEM …

【Spring Boot】SpringBoot完整实现社交网站系统

一个完整的社交网站系统需要涉及到用户登录、发布动态、关注、评论、私信等各方面。这里提供一个简单的实现示例&#xff0c;供参考。 前端代码 前端使用Vue框架&#xff0c;以下是部分代码示例&#xff1a; 登录页&#xff1a; <template><div><input type…

论文阅读:Model-Agnostic Meta-Learning for Fast Adaptation of Deep Networks

前言 要弄清MAML怎么做&#xff0c;为什么这么做&#xff0c;就要看懂这两张图。先说MAML**在做什么&#xff1f;**它是打着Mate-Learing的旗号干的是few-shot multi-task Learning的事情。具体而言就是想训练一个模型能够使用很少的新样本&#xff0c;快速适应新的任务。 定…

pdf转ppt软件哪个好用?推荐一个好用的pdf转ppt软件

在日常工作和学习中&#xff0c;我们经常会遇到需要将PDF文件转换为PPT格式的情况。PDF格式的文件通常用于展示和保留文档的原始格式&#xff0c;而PPT格式则更适合用于演示和展示。为了满足这一需求&#xff0c;许多软件提供了PDF转PPT的功能&#xff0c;使我们能够方便地将PD…

vscode免密连远程

一、本地操作 ssh-keygen cd ~/.ssh ls // config为安装vscode远程插件后的信息 // id_rsa为本地私钥 // id_rsa.pub为本地公钥 vim config // 在User下增加一行本地私钥地址 IdentityFile "/Users/xuerui/.ssh/id_rsa"二、远程 cd ~/.ssh vim authorized_keys //…

C语言暑假刷题冲刺篇——day5

目录 一、选择题 二、编程题 &#x1f388;个人主页&#xff1a;库库的里昂 &#x1f390;CSDN新晋作者 &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏✨收录专栏&#xff1a;C语言每日一练✨相关专栏&#xff1a;代码小游戏、C语言初阶、C语言进阶&#x1f91d;希望作者…

【CSS】CSS 特性 ( CSS 优先级 | 优先级引入 | 选择器基本权重 )

一、CSS 优先级 1、优先级引入 定义 CSS 样式时 , 可能出现 多个 类型相同的 规则 定义在 同一个元素上 , 如果 CSS 选择器 相同 , 执行 CSS 层叠性 , 根据 就近原则 选择执行的样式 , 如 : 出现两个 div 标签选择器 , 都设置 color 文本颜色 ; <style>div {color: re…

精准高效农业作业,植保无人机显身手

中国作为农业大国&#xff0c;拥有约18亿亩的农田&#xff0c;每年都需要进行种子喷洒和农药施用等农业作业&#xff0c;对于普通农户来说&#xff0c;这是一项耗时耗力的工程&#xff0c;同时&#xff0c;人工喷洒农药极易造成农药慢性中毒&#xff0c;对农民的身体健康产生极…

Redis——急速安装并设置自启(CentOS)

现状 对于开发人员来说&#xff0c;部署服务器环境并不是一个高频操作。所以就导致绝大部分开发人员不会花太多时间去学习记忆&#xff0c;而是直接百度&#xff08;有一些同学可能连链接都懒得收藏&#xff09;。所以到了部署环境的时候就头疼&#xff0c;甚至是抗拒。除了每次…

k8s 安装istio (一)

前置条件 已经完成 K8S安装过程十&#xff1a;Kubernetes CNI插件与CoreDNS服务部署 部署 istio 服务网格与 Ingress 服务用到了 helm 与 kubectl 这两个命令行工具&#xff0c;这个命令行工具依赖 ~/.kube/config 这个配置文件&#xff0c;目前只在 kubernetes master 节点中…

web前端开发中的响应式布局设计是什么意思?

响应式布局是指网页设计和开发中的一种技术方法&#xff0c;旨在使网页能够在不同大小的屏幕和设备上都能良好地显示和交互。这种方法使得网页可以自动适应不同的屏幕尺寸&#xff0c;包括桌面电脑、平板电脑和手机等。 在Web前端开发中&#xff0c;响应式布局通常使用CSS&…

随记-Kibana Dev Tools,ES 增删改查 索引,Document

索引 创建索引 创建索引 PUT index_test创建索引 并 修改分片信息 # 创建索引 并 修改分片信息 PUT index_test2 { # 必须换行, PUT XXX 必须独占一行&#xff0c;类似的 其他请求也需要独占一行 "settings": {"number_of_shards": 1, # 主分片"…

bug复刻,解决方案---在改变div层级关系时,导致传参失败

问题描述&#xff1a; 在优化页面时&#xff0c;为了实现网页顶部遮挡效果&#xff08;内容滚动&#xff0c;顶部导航栏不随着一起滚动&#xff0c;并且覆盖&#xff09;&#xff0c;做法是将内容都放在一个div里面&#xff0c;为这个新的div设置样式&#xff0c;margin-top w…

c++ qt--事件过滤(第七部分)

c qt–事件过滤&#xff08;第七部分&#xff09; 一.为什么要用事件过滤 上一篇博客中我们用到了事件来进行一些更加细致的操作&#xff0c;如监控鼠标的按下与抬起&#xff0c;但是我们发现如果有很多的组件那每个组件都要创建一个类&#xff0c;这样就显得很麻烦&#xff…

GO语言:Worker Pools线程池、Select语句、Metex互斥锁详细示例教程

目录标题 一、Buffered Channels and Worker Pools1. Goroutine and Channel Example 线程和通道示例2. Deadlock 死锁3. Closing buffered channels 关闭通道4. Length vs Capacity 长度和容量5. WaitGroup6. Worker Pool Implementation 线程池 二、Select1. Example2. Defau…

IO进程线程,文件与目录,实现linux任意目录下ls -la

注意文件的名字、路径是如何输入的。 函数opendir打开目录&#xff0c;struct dirent&#xff0c;struct stat这些结构体的含义。 readdir()函数是一个用于读取目录内容的系统调用或库函数&#xff0c;在类Unix操作系统中&#xff08;如Linux&#xff09;广泛使用。它用于遍历…

python爬虫10:selenium库

python爬虫10&#xff1a;selenium库 前言 ​ python实现网络爬虫非常简单&#xff0c;只需要掌握一定的基础知识和一定的库使用技巧即可。本系列目标旨在梳理相关知识点&#xff0c;方便以后复习。 申明 ​ 本系列所涉及的代码仅用于个人研究与讨论&#xff0c;并不会对网站产…

leetcode算法题--复杂链表的复制

原题链接&#xff1a;https://leetcode.cn/problems/fu-za-lian-biao-de-fu-zhi-lcof/description/?envTypestudy-plan-v2&envIdcoding-interviews 感觉一开始想到的办法还是比较笨 /*** Definition for a Node.* type Node struct {* Val int* Next *Node* …

C语言练习题Day1

从今天开始分享C语言的练习题&#xff0c;每天都分享&#xff0c;差不多持续16天&#xff0c;看完对C语言的理解可能更进一步&#xff0c;让我们开始今天的分享吧&#xff01; 题目一 执行下面的代码&#xff0c;输出结果是&#xff08;&#xff09; int x5,y7; void swap()…

Qt --- 对象树机制、析构顺序导致崩溃

{QWidget widget;QPushButton buttonQuit("Quit",&widget); } 作为父组件的widget&#xff0c;子组件buttonQuit都是QObject的子类&#xff1b;上述代码运行没有问题。 代码析构时&#xff0c;因为C的要求&#xff0c;局部对象的析构时按照实例化顺序逆向的顺序…