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内核》 宋宝华 编著,机械工业出版社

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

最佳的6款原型设计工具

在验证方案原型时,具有较高还原度和清晰信息结构的原型可以使用户更容易理解解决方案的想法,并表达他们的意见。良好的原型是验证方案的有效基础。本文介绍 6 个专业易用的原型工具可以帮助您快速制作可验证的方案原型,减少产品、运营和其他同…

单片机接收PC发出的数据

#include<reg51.h> //包含单片机寄存器的头文件 /***************************************************** 函数功能&#xff1a;接收一个字节数据 ***************************************************/ unsigned char Receive(void) { unsigned char dat; …

【开源】SpringBoot框架开发超市账单管理系统 JAVA+Vue+SpringBoot+MySQL

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、系统设计3.1 总体设计3.2 前端设计3.3 后端设计在这里插入图片描述 四、系统展示五、核心代码5.1 查询供应商5.2 查询商品5.3 新增超市账单5.4 编辑超市账单5.5 查询超市账单 六、免责说明 一、摘要 1.1 项目介绍 基于…

img图片鉴权附加token

<img 标签预览图片如何携带token进行验证 前言 vue中给img的src添加token 因项目中安全测评的需要&#xff0c;请求图片时要求添加token&#xff0c;方法如下&#xff1a;在项目中循环渲染的img标签中的图片要显示&#xff0c;src需要加请求头token&#xff08;正常情况下&…

【NLP 自然语言处理(一)---词向量】

文章目录 什么是NLP自然语言处理发展历程自然语言处理模型模型能识别单词的方法词向量分词 一个向量vector表示一个词词向量的表示-one-hot多维词嵌入word embeding词向量的训练方法 CBOW Skip-gram词嵌入的理论依据 一个vector&#xff08;向量&#xff09;表示短语或者文章ve…

这些企业已经有了HCM系统,为什么还要再单独上考勤系统?

最近有几家制造业和零售业的朋友咨询我考勤管理系统选型的问题&#xff0c;都集中在WFM方面的考勤咨询。 奇怪的是这些企业基本上都有一定的HR数字化基础&#xff0c;也上了HR主系统&#xff0c;甚至也实施了考勤系统&#xff0c;那为什么还要再上一个考勤系统呢&#xff1f; …

[Python] opencv - 什么是直方图?如何绘制图像的直方图?如何对直方图进行均匀化处理?

什么是直方图&#xff1f; 直方图是一种统计图&#xff0c;用于展示数据的分布情况。它将数据按照一定的区间或者组进行划分&#xff0c;然后计算在每个区间或组内的数据频数或频率&#xff08;即数据出现的次数或占比&#xff09;&#xff0c;然后用矩形或者柱形图的形式将这…

基于java+springboot+vue实现的高校物品捐赠管理系统(文末源码+Lw)23-151

第1章 绪论 当前的网络技术&#xff0c;软件技术等都具备成熟的理论基础&#xff0c;市场上也出现各种技术开发的软件&#xff0c;这些软件都被用于各个领域&#xff0c;包括生活和工作的领域。随着电脑和笔记本的广泛运用&#xff0c;以及各种计算机硬件的完善和升级&#xf…

C语言:函数

创作不易&#xff0c;友友们给个三连吧&#xff01;&#xff01; 一、函数的概念 数学中我们见过函数的概念&#xff0c;例如ykxb&#xff0c;k和b都是常数&#xff0c;给任意一个x就可以得到y 而C语言也引入了函数&#xff08;function&#xff09;这个概念&#xff0c;C语…

代码随想录算法训练营Day21|二叉搜索树的最小绝对差、二叉搜索树中的众数、二叉树的最近公共祖先

二叉搜索树的最小绝对差 思路1&#xff1a;将二叉搜索树转化成一个有序数组&#xff0c;在有序数组上求两个数的最小值差。 只需要遍历有序数组&#xff0c;统计出最小值差 class Solution{ private:vector<int>vec;void traversal(TreeNode* root){if(root NULL)ret…

H5 简约四色新科技风引导页源码

H5 简约四色新科技风引导页源码 源码介绍&#xff1a;一款四色切换自适应现代科技风动态背景的引导页源码&#xff0c;源码有主站按钮&#xff0c;分站按钮2个&#xff0c;QQ联系站长按钮一个。 下载地址&#xff1a; https://www.changyouzuhao.cn/11990.html

Windows 启动项无法打开 Aanconda 问题。pyqt noBinding

windows中点击Anaconda navigator 没有反应: ## 解决 (右键运行Anaconda prompt) 以管理员身份运行&#xff1a; 分别运行以下命令&#xff1a; conda update conda conda update anaconda-navigatorpip uninstall PyQt5 pip install PyQt5 pip install pyqtwebengine

5年前端仔的2023年终总结

突然发现已经有好几个月没有写过博客总结过什么&#xff0c;小小辩解一下&#xff0c;其实并不是笔者停止的学习和总结&#xff0c;随着在前端这个行业的逐年深入&#xff0c;渐渐的很多收获不再是像之前简单的技术点的确定性描述讲解了&#xff0c;而是某个领域的知识体系的串…

『运维备忘录』之 TAR 命令详解

运维人员不仅要熟悉操作系统、服务器、网络等只是&#xff0c;甚至对于开发相关的也要有所了解。很多运维工作者可能一时半会记不住那么多命令、代码、方法、原理或者用法等等。这里我将结合自身工作&#xff0c;持续给大家更新运维工作所需要接触到的知识点&#xff0c;希望大…

机器学习-线性回归法

线性回归算法 解决回归问题思想简单&#xff0c;实现容易许多强大的非线性模型的基础结果具有很好的可解释性蕴含机器学习中的很多重要思想 样本特征只有一个&#xff0c;称为&#xff1a;简单线性回归 通过分析问题&#xff0c;确定问题的损失函数或者效用函数 通过最优化…

jsp课程管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 课程管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0&…

Termux配置安卓编译环境

前言 Termux安装后&#xff0c;就相当于把手机变成了一台Linux服务器&#xff0c;而且现在手机卡通常是能拿到ipv6公网地址的&#xff0c;所以&#xff0c;这个服务器能干啥&#xff1f; 编程搭建网站跑脚本 本文讲述的就是怎么在Termux搭建安卓编译环境&#xff0c;实现手机…

CV | Medical-SAM-Adapter论文详解及项目实现

******************************* &#x1f469;‍⚕️ 医学影像相关直达&#x1f468;‍⚕️******************************* CV | SAM在医学影像上的模型调研【20240207更新版】-CSDN博客 CV | Segment Anything论文详解及代码实现 本文主要讲解Medical-SAM-Adapter论文及项…

HTML 样式学习手记

HTML 样式学习手记 在探索网页设计的世界时&#xff0c;我发现HTML元素的样式调整真的是个很酷的环节。通过简单的属性设置&#xff0c;就能让文字换上五彩斑斓的颜色、变换各异的字体和大小。特别是那个style属性&#xff0c;感觉就像是一扇通往CSS魔法世界的大门。 代码小试…

【Python】虚拟环境miniconda安装(python3.7, python3.x)

背景 使用Python开发项目时&#xff0c;我们一般都需要安装环境&#xff0c;可能是在物理机上直接安装&#xff0c;也可能是在虚拟环境上安装&#xff0c;当前是怎么按照conda环境的示例&#xff0c;可以指定安装Python3.x的所有版本。 安装 首先&#xff0c;需要登录当前的…