基于 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,一经查实,立即删除!

相关文章

论文阅读: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…

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;对农民的身体健康产生极…

k8s 安装istio (一)

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

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…

python爬虫10:selenium库

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

C语言练习题Day1

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

「MySQL-01」MySQL基础

目录 一、数据库概念 1. 什么是数据库 2. 为什么要有数据库&#xff1f; 3. 数据库将数据存在哪里&#xff1f; 二、知名数据库介绍 1.知名数据库介绍 2.为什么要学习MySQL 三、MySQL的基本使用 0. 安装MySQL 1. 数据库客户端链接服务端 2. Windows下的MySQL服务端管理 3. 数据…

昌硕科技、世硕电子同步上线法大大电子合同

近日&#xff0c;世界500强企业和硕联合旗下上海昌硕科技有限公司&#xff08;以下简称“昌硕科技”&#xff09;、世硕电子&#xff08;昆山&#xff09;有限公司&#xff08;以下简称“世硕电子”&#xff09;的电子签项目正式上线。上线仪式在上海浦东和硕集团科研大楼举行&…

使用fastjson2的@JSONField注解解决日期格式记录

最近在做一个三方对接&#xff0c;对方的日期格式数据要求时间日期格式: yyyyMMddHHmmss或者 yyyyMMdd&#xff0c;我一下想起了fastjson2工具包&#xff0c;所以很愉快的解决了此问题。 依赖jar如下&#xff1a; <dependency><groupId>com.alibaba.fastjson2</…

每日一博 - 闲聊云原生和容器编排

文章目录 概念1. 云原生&#xff08;Cloud Native&#xff09;&#xff1a;2. 容器编排&#xff08;Container Orchestration&#xff09;&#xff1a; 小结 概念 云原生和容器编排是两个不同的概念&#xff0c;但它们之间有着密切的联系。下面将分别介绍这两个概念&#xff0…

【C++】const成员 | 取地址运算符重载

Ⅰ. const成员 两种const 我们知道&#xff0c;用const修饰 能起到保护&#xff0c;使之不被修改的作用。 修饰指针的const有两种位置&#xff1a; 我们学过的this指针&#xff0c;就被后者所修饰&#xff0c;因此无法被修改。 const成员函数 ➡️为了保护函数里的成员&…

《Java极简设计模式》第05章:原型模式(Prototype)

作者&#xff1a;冰河 星球&#xff1a;http://m6z.cn/6aeFbs 博客&#xff1a;https://binghe.gitcode.host 文章汇总&#xff1a;https://binghe.gitcode.host/md/all/all.html 源码地址&#xff1a;https://github.com/binghe001/java-simple-design-patterns/tree/master/j…

Elasticsearch 8.X reindex 源码剖析及提速指南

1、reindex 源码在线地址 为方便大家验证&#xff0c;这里给出 reindex github 源码地址。 https://github.com/elastic/elasticsearch/blob/001fcfb931454d760dbccff9f4d1b8d113f8708c/server/src/main/java/org/elasticsearch/index/reindex/ReindexRequest.java reindex 常见…

开源软件的崛起:历史与未来

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

Lambda函数

一.概念 1.利用lambda表达式可以编写内嵌的匿名函数&#xff0c;用以替换独立函数或者函数对象 2.每当你定义一个lambda表达式后&#xff0c;编译器会自动生成一个匿名类&#xff08;这个类当前重载了&#xff08;&#xff09;运算符&#xff09;&#xff0c;我们称为闭包类型…

Lazada商品详情接口 获取Lazada商品详情数据 Lazada商品价格接

一、引言 随着电子商务的迅速发展和普及&#xff0c;电商平台之间的竞争也日趋激烈。为了提供更好的用户体验和更高效的后端管理&#xff0c;Lazada作为东南亚最大的电商平台之一&#xff0c;开发了一种商品详情接口&#xff08;Product Detail API&#xff09;。该接口允许第…