当前位置: 首页 > news >正文

Linux内核与驱动面试经典“小”问题集锦(4)

接前一篇文章:Linux内核与驱动面试经典“小”问题集锦(3)

问题5

问:Linux内核中内存分配都有哪些方式?它们之间的使用场景都是什么?

备注:这个问题是笔者近期参加蔚来面试时遇到的一个问题。这道题说是一道小题,其实应该是一道大题,它考察的是候选者对于Linux内存管理子系统中内存分配这一块的功力深浅。

答:

在Linux内核空间中,申请内存所涉及的函数主要包括kmalloc()、__get_free_pages()和vmalloc()等。其中,kmalloc()和__get_free_pages()(及其类似函数)申请的内存位于DMA和常规区域的映射区,而且在物理上也是连续的,它们与真实的物理地址只有一个固定的偏移,因此存在较简单的转换关系;而vmalloc()在虚拟内存空间给出一块连续的内存区。实质上,这片连续的虚拟内存在物理内存中并不一定连续,而vmalloc()申请的虚拟内存和物理内存之间也没有简单的换算关系。

1. kmalloc()

kmalloc函数在include/linux/slab.h中,代码如下:

static __always_inline __alloc_size(1) void *kmalloc(size_t size, gfp_t flags)
{if (__builtin_constant_p(size) && size) {unsigned int index;if (size > KMALLOC_MAX_CACHE_SIZE)return kmalloc_large(size, flags);index = kmalloc_index(size);return kmalloc_trace(kmalloc_caches[kmalloc_type(flags, _RET_IP_)][index],flags, size);}return __kmalloc(size, flags);
}

kmalloc函数的第一个参数是要分配的块的大小;第二个参数为分配标志,用于控制kmalloc()的行为。

最常用的分配标志是GFP_KERNEL,其含义是在内核空间的进程中申请内存。kmalloc()的底层依赖于__get_free_pages()来实现,分配标志的前缀GFP正好是这个底层函数的缩写。使用GFP_KERNEL标志申请内存时,若暂时不能满足,则进程会休眠等待页,即会引起阻塞,因此不能在中断上下文或持有自旋锁的时候使用GFP_KERNEL申请内存

备注:这也是经常会被问到的一道经典面试题,即GFP_KERNEL能否用在中断中?或者中断中应该使用哪些标志?

由于在中断处理函数、tasklet和内核定时器等非进程上下文中不能阻塞,所以此时驱动应当使用GFP_ATOMIC标志来申请内存。当使用GFP_ATOMIC标志申请内存时,若不存在空闲页,则不等待,直接返回。

其它的申请标志还包括:

  • GFP_USER:用来为用户空间页分配内存,可能阻塞。
  • GFP_HIGHUSER:类似于GFP_USER,但它从高端内存分配。
  • GFP_DMA:从DMA区域分配内存,
  • GFP_NOIO:不允许任何I/O初始化。
  • GFP_NOFS:不允许任何文件系统调用。
  • __GFP_HIGHMEM:指示分配的内存可以位于高端内存。
  • __GFP_COLD:请求一个较长时间不访问的页。
  • __GFP_NOWARN:当一个分配无法满足时,阻止内核发出警告。
  • __GFP_HIGH:高优先级请求,允许获得被内核保留给紧急情况使用的最后的内存页。
  • __GFP_REPEAT:分配失败,则尽力重复尝试。
  • __GFP_NOFAIL:只许申请成功,不许失败。不推荐使用此标志。
  • __GFP_NORETRY:若申请不到,则立即放弃。

使用kmalloc()申请的内存应该使用kfree()释放,这个函数的用法和用户空间的free()类似。

2. __get_free_pages()

__get_free_pages()系列函数/宏本质上是Linux内核最底层用于获取空闲内存的方法,因为底层的buddy(伙伴)算法以2^n页为单位管理空闲内存,因此最底层的内存申请总是以2^n页为单位的。

__get_free_pages()系列函数/宏包括get_zeroed_page()、__get_free_page()和__get_free_pages()。

  • get_zeroed_page()

该函数返回一个指向新页的指针,并且将该页清零。其在mm/page_alloc.c中,代码如下:

unsigned long get_zeroed_page(gfp_t gfp_mask)
{return __get_free_page(gfp_mask | __GFP_ZERO);
}
EXPORT_SYMBOL(get_zeroed_page);
  • __get_free_page();

该宏返回一个指向新页的指针,但该页不清零。其定义在include/linux/gfp.h中,如下:是:

#define __get_free_page(gfp_mask) \__get_free_pages((gfp_mask), 0)

它实际上就是调用了下边的__get_free_pages()申请一页。

  • __get_free_pages()

__get_free_pages()也是在mm/page_alloc.c中,代码如下:

/** Common helper functions. Never use with __GFP_HIGHMEM because the returned* address cannot represent highmem pages. Use alloc_pages and then kmap if* you need to access high mem.*/
unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)
{struct page *page;page = alloc_pages(gfp_mask & ~__GFP_HIGHMEM, order);if (!page)return 0;return (unsigned long) page_address(page);
}
EXPORT_SYMBOL(__get_free_pages);

该函数可分配多个页,并返回所分配内存的首地址。分配的页数为2^order,分配的页不清零。oeder允许的最大值是10(1024页)或者11(2048页),这取决于具体的硬件平台。

__get_free_pages()和get_zeroed_page()在实现中调用了alloc_pages函数,alloc_pages()既可以在内核空间分配,也可以在用户空间分配。该函数也在mm/page_alloc.c中,其原型如下:

struct page *__alloc_pages(gfp_t gfp, unsigned int order, int preferred_nid,nodemask_t *nodemask);

其参数含义与__get_free_pages()相似,但它返回分配的第一个页的描述符而非首地址。

3. vmalloc

vmalloc()一般只为存在于软件中(没有对应的硬件意义)的较大的顺序缓冲区分配内存。vmalloc()远大于__get_free_pages()的开销。为了完成vmalloc(),新的页表项需要被建立。因此,只是调用vmalloc()来分配少量的内存(如1页以内的内存)是不妥的。

vmalloc函数在mm/vmalloc.c中,代码如下:

/*** vmalloc - allocate virtually contiguous memory* @size:    allocation size** Allocate enough pages to cover @size from the page level* allocator and map them into contiguous kernel virtual space.** For tight control over page level allocator and protection flags* use __vmalloc() instead.** Return: pointer to the allocated memory or %NULL on error*/
void *vmalloc(unsigned long size)
{return __vmalloc_node(size, 1, GFP_KERNEL, NUMA_NO_NODE,__builtin_return_address(0));
}
EXPORT_SYMBOL(vmalloc);

vmalloc函数在申请内存时,会进行内存的映射,改变页表项,而不像kmalloc()实际用的是开机过程中就映射好了的DMA和常规区域的页表项。因此,vmalloc()的虚拟地址和物理地址不是一个简单的线性映射。

vmalloc函数不能用在原子上下文中,因为其内部实现使用了标志位GFP_KERNEL的kmalloc()。

这里多说一点。关于kmalloc与vmalloc的区别,参见笔者的这篇文章:中移(苏州)软件技术有限公司面试问题与解答(7)—— kmalloc与vmalloc的区别与联系及使用场景。

以上是从具体的内存分配函数的角度来说的。从更大的层面来讲,Linux内核物理内存分配的一般方式包括

(1)伙伴系统(Buddy System)

伙伴系统将物理内存划分为不同大小的块,每个块大小都是2的幂次。这些块被组织成“伙伴”对,每对伙伴的大小是一样的。

(2)slab分配器

slab分配器用于管理小块内存分配,如内核数据结构的分配。slab分配器将内存划分为不同的对象缓存,以提高内存分配和释放的效率。

(3)CMA(Contiguous Memory Allocator,连续内存分配器)

对于需要连续大块内存的需求,Linux引入了CMA。它可以用于分配连续的物理内存区域,如视频缓冲等。

(4)页分配器

Linux内核将物理内存划分为固定大小的页,通常是4KB。当进程需要内存时,内核会使用页分配器来分配这些页面。

(5)内存回收

Linux内核还会定期执行内存回收,以回收未使用的内存。这包括清除不再使用的页面,并将其返回到内存池中。

可见,本题虽然看似是一道面试小题,但实际上其背后蕴含的知识点是非常丰富的,也是非常考验功力的。

参考资料:

《Linux设备驱动开发详解 —— 基于最新的Linux 4.0内核》 宋宝华 编著,机械工业出版社

相关文章:

Linux内核与驱动面试经典“小”问题集锦(4)

接前一篇文章:Linux内核与驱动面试经典“小”问题集锦(3) 问题5 问:Linux内核中内存分配都有哪些方式?它们之间的使用场景都是什么? 备注:这个问题是笔者近期参加蔚来面试时遇到的一个问题。这…...

使用python实现:判断任意坐标点在STL几何模型的内部或外部

简介 在STL几何模型处理的过程中,经常需要判断一个点是否在模型的内部。网上给出的资料主要是使用C vtk的,而python vtk的很少。本文给出了一段精简版的python代码,实现判断任意坐标点在STL几何模型的内部或外部。 代码 首先定义三个函数 …...

leetcode(滑动窗口)483.找到字符中所有字母异位词(C++详细解释)DAY4

文章目录 1.题目示例提示 2.解答思路3.实现代码结果 4.总结 1.题目 给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。 异位词 指由相同字母重排列形成的字符串(包括相同的字符串&a…...

Leaf——美团点评分布式ID生成系统

0.普通算法生成id的缺点 1.Leaf-segment数据库方案 第一种Leaf-segment方案,在使用数据库的方案上,做了如下改变: - 原方案每次获取ID都得读写一次数据库,造成数据库压力大。改为利用proxy server批量获取,每次获取一…...

ProcessSlot构建流程分析

ProcessorSlot ProcessorSlot构建流程 // com.alibaba.csp.sentinel.CtSph#lookProcessChain private Entry entryWithPriority(ResourceWrapper resourceWrapper, int count, boolean prioritized, Object... args)throws BlockException {// 省略创建 Context 的代码// 黑盒…...

工业笔记本丨行业三防笔记本丨亿道加固笔记本定制丨极端温度优势

工业笔记本是专为在恶劣环境条件下工作而设计的高度耐用的计算机设备。与传统消费者级笔记本电脑相比,工业笔记本在极端温度下展现出了许多优势。本文将探讨工业笔记本在极端温度环境中的表现,并介绍其优势。 耐高温性能: 工业笔记本具有更高的耐高温性…...

游戏服务器多少钱一台?腾讯云32元,阿里云26元

游戏服务器租用多少钱一年?1个月游戏服务器费用多少?阿里云游戏服务器26元1个月、腾讯云游戏服务器32元,游戏服务器配置从4核16G、4核32G、8核32G、16核64G等配置可选,可以选择轻量应用服务器和云服务器,阿腾云atengyu…...

实战分享:SpringBoot在创新创业项目管理中的应用

✍✍计算机编程指导师 ⭐⭐个人介绍:自己非常喜欢研究技术问题!专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目:有源码或者技术上的问题欢迎在评论区一起讨论交流! ⚡⚡ Java实战 |…...

vue3:28— Vue 2 对 Vue 3 的所有非兼容性改变。(vue3学习笔记终)

非兼容性改变 | Vue 3 迁移指南 过渡类名v-enter 修改为 v-enter-from、过渡类名 v-leave 修改为 v-leave-from 。keyCode 作为 v-on 修饰符的支持。v-model 指令在组件上的使用已经被重新设计,替换掉了v-bind.sync.v-if 和 v-for 在同一个元素身上使用时的优先级发…...

【学习笔记】TypeScript学习笔记1 --TypeScript中的类型

文章目录 TS总的变量类型References TS总的变量类型 备注: 如果一个变量设置为了any 类型之后相当于变量关闭了TS的类型检测 let d: any; d 10; d hello;//unknown表示的是未知类型,实际是上一个安全的any,unknown类型的变量不能直接赋值给其他变量le…...

矩阵的正定(positive definite)性质的作用

1. 定义 注意,本文中正定和半正定矩阵不要求是对称或Hermite的。 2. 性质 3. 作用 (1)Axb直接法求解 cholesky实对称正定矩阵求解复共轭对称正定矩阵求解LDL实对称非正定矩阵求解复共轭对称非正定矩阵求解复对称矩阵求解LU实非对称矩阵求解…...

用python编写爬虫,爬取房产信息

题目 报告要求 工程报告链接放在这里 https://download.csdn.net/download/Samature/88816284使用 1.安装jupyter notebook 2.用jupyter notebook打开工程里的ipynb文件,再run all就行 注意事项 可能遇到的bug 暂无,有的话私信我...

Swift Combine 从入门到精通一

1. Combine 简介 用 Apple 官方的话来说,Combine 是: a declarative Swift API for processing values over time. Combine 是 Apple 用来实现函数响应式编程的库, 类似于 RxSwift。 RxSwift 是 ReactiveX 对 Swift 语言的实现。 Combine 使用了许多可以…...

探索前端开发框架:React、Angular 和 Vue 的对决(一)

🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…...

企业飞书应用机器人,使用python发送图文信息到群

企业飞书应用的自动化,需要创建企业应用,应用开通机器人能力,并获取机器人所需的app_id与app_secret(这一部分大家可以在飞书的控制台获取:https://open.feishu.cn/api-explorer/) 文章目录 步骤1&#xff…...

设计模式1-访问者模式

访问者模式是一种行为设计模式,它允许你定义在对象结构中的元素上进行操作的新操作,而无需修改这些元素的类。这种模式的主要思想是将算法与元素的结构分离开,使得可以在不修改元素结构的情况下定义新的操作。 所谓算法与元素结构分离&#x…...

Android meminfo 查看方法及解析

目录 Android 上查看memory 信息的方法 内存限制的信息 手动释放缓存 例 adb shell dumpsys meminfo pid 解析 adb shell dumpsys meminfo 汇总信息说明 Total RAM Free RAM ION Used RAM Lost RAM ZRAM /proc/meminfo 参考文档 Android 上查看memory 信息的方法 …...

微信小程序解决华为手机保存图片到相册失败

1.新增隐私设置 2.优化代码 新增uni.authorize判断 _saveCode() {let that this;console.log(点击了保存图片)console.log(this.result)uni.authorize({scope: scope.writePhotosAlbum,success(e) {console.log(e)if (this.result ! "") {uni.saveImageToPhotosAlb…...

板块零 IDEA编译器基础:第三节 下载和在IDEA中集成 Tomcat服务器 来自【汤米尼克的JAVAEE全套教程专栏】

板块零 IDEA编译器基础:第三节 下载和在IDEA中集成 Tomcat服务器 一、为什么选择Tomcat(1)常见的JAVA WEB服务器(2)选择Tomcat的理由 二、Tomcat 8.5下载解压三、Tomcat 结构目录四、在IDEA中集成Tomcat 假设我们已经…...

2024/2/6

一、填空题 1、一个类的头文件如下所示&#xff0c;num初始化值为5&#xff0c;程序产生对象T&#xff0c;且修改num为10&#xff0c;并使用show()函数输出num的值10。 #include <iostream.h> class Test { private: static int num; public: Test(int); void sho…...

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周&#xff0c;有很多同学在写期末Java web作业时&#xff0c;运行tomcat出现乱码问题&#xff0c;经过多次解决与研究&#xff0c;我做了如下整理&#xff1a; 原因&#xff1a; IDEA本身编码与tomcat的编码与Windows编码不同导致&#xff0c;Windows 系统控制台…...

OpenLayers 可视化之热力图

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 热力图&#xff08;Heatmap&#xff09;又叫热点图&#xff0c;是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程&#xff1a;&#xff08;白话解释&#xff09; 我们将原始待发送的消息称为 M M M&#xff0c;依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)&#xff08;意思就是 G &#xff08; x ) G&#xff08;x) G&#xff08;x) 是已知的&#xff09;&#xff0…...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

Spring AI与Spring Modulith核心技术解析

Spring AI核心架构解析 Spring AI&#xff08;https://spring.io/projects/spring-ai&#xff09;作为Spring生态中的AI集成框架&#xff0c;其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似&#xff0c;但特别为多语…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索&#xff08;基于物理空间 广播范围&#xff09;2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

安卓基础(aar)

重新设置java21的环境&#xff0c;临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的&#xff1a; MyApp/ ├── app/ …...

云原生玩法三问:构建自定义开发环境

云原生玩法三问&#xff1a;构建自定义开发环境 引言 临时运维一个古董项目&#xff0c;无文档&#xff0c;无环境&#xff0c;无交接人&#xff0c;俗称三无。 运行设备的环境老&#xff0c;本地环境版本高&#xff0c;ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...

LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf

FTP 客服管理系统 实现kefu123登录&#xff0c;不允许匿名访问&#xff0c;kefu只能访问/data/kefu目录&#xff0c;不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...

GitFlow 工作模式(详解)

今天再学项目的过程中遇到使用gitflow模式管理代码&#xff0c;因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存&#xff0c;无论是github还是gittee&#xff0c;都是一种基于git去保存代码的形式&#xff0c;这样保存代码…...