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

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

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

相关文章

React+Antd实现省、市区级联下拉多选组件(支持只选省不选市)

1、效果 是你要的效果,咱们继续往下看,搜索面板实现省市区下拉,原本有antd的Cascader组件,但是级联组件必须选到子节点,不能只选省,满足不了页面的需求 2、环境准备 1、react18 2、antd 4 3、功能实现 …

【制作100个unity游戏之23】实现类似七日杀、森林一样的生存游戏14(附项目源码)

本节最终效果演示 文章目录 本节最终效果演示系列目录前言给树添加动画摇晃动画 效果(后补效果)源码完结 系列目录 前言 欢迎来到【制作100个Unity游戏】系列!本系列将引导您一步步学习如何使用Unity开发各种类型的游戏。在这第23篇中&…

春节回家坐飞机后助听器就不好用了?如何过安检、拖运?

春节即将来临,很多人都要乘坐飞机回家或者出游。如果你是一位助听器使用者,你可能会有一些疑问:坐飞机能戴助听器吗?助听器会不会受到安检设备的影响?直接将助听器放在传送带上可以吗?……别担心&#xff0…

RabbitMQ-5.消费者的可靠性

消费者的可靠性 5.消费者的可靠性5.1.消费者确认机制5.2.失败重试机制5.3.失败处理策略5.4.业务幂等性5.4.1.唯一消息ID5.4.2.业务判断 5.5.兜底方案 5.消费者的可靠性 当RabbitMQ向消费者投递消息以后,需要知道消费者的处理状态如何。因为消息投递给消费者并不代表…

U盘显示空间小于实际U盘空间的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

2024年【陕西省安全员C证】试题及解析及陕西省安全员C证复审考试

题库来源:安全生产模拟考试一点通公众号小程序 陕西省安全员C证试题及解析是安全生产模拟考试一点通总题库中生成的一套陕西省安全员C证复审考试,安全生产模拟考试一点通上陕西省安全员C证作业手机同步练习。2024年【陕西省安全员C证】试题及解析及陕西…

Java玩转《啊哈算法》解密回文之栈

菩萨清凉月,常游毕竟空,众生心垢净,菩提影现中。 这目录 这开头这代码地址栈案例代码优化建议类似扩展 这开头 各位女士们,先生们好!本人最近在看《啊哈算法》,这本书写的确实还可以,很有趣味性…

IEC 104电力规约详细解读(三) - 遥信

1.功能简述 遥信,、即状态量,是为了将断路器、隔离开关、中央信号等位置信号上送到监控后台的信息。遥信信息包括:反应电网运行拓扑方式的位置信息。如断路器状态、隔离开关状态;反应一次二次设备工作状况的运行信息,如…

Leetcode刷题-(11~15)-Java+Python+JavaScript

算法是程序员的基本功,也是各个大厂必考察的重点,让我们一起坚持写算法题吧 遇事不决,可问春风,春风不语,即是本心。 我们在我们能力范围内,做好我们该做的事,然后相信一切都事最好的安排就可…

考研数据结构笔记(3)

顺序表存储结构 存储结构顺序结构定义基本操作的实现静态分配问题 动态分配代码功能 顺序表的特点: 顺序表小结顺序表的插入删除插入删除小结 顺序表的查找按位查找按值查找小结 存储结构 顺序结构 定义 线性表是具有相同数据类型的n(n>0)个数据元素的有限序列(每个数据元素…

JavaScript流程控制详解之循环结构(倒三角、九九乘法表)

循环结构 在JavaScript中,循环语句指的是在满足某个条件下重复执行 指定的一段代码。若条件结果为true,则重复执行,则进入循环,否则结束循环。 在JavaScript中,循环语句如下: while语句do…while语句for语句 while…

shell脚本基础语法(.sh ./ sh bash source shell)

Linux 之 Shell 脚本基础语法 0. 学习一门语言的顺序 1. Shell 编程概述 1.1 Shell 名词解释 在 Linux 操作系统中,Shell 是一个命令行解释器,它为用户提供了一个与操作系统内核交互的界面。用户可以通过 Shell 输入命令,然后 Shell 将这些…

ONLYOFFICE 文档开发者版 8.0:API和文档生成器更新

随着 8.0 版新功能的发布,我们更新了编辑器、文档生成器和插件的 API。请阅读本文了解详情。 PDF 支持 我们在 documentType 参数中添加了 pdf 文档这一类型。现在完全支持PDF文件*,包括含有可填写字段的文件,并且可以在ONLYOFFICE PDF 编辑…

深入了解Spring Expression Language(SpEL)

深入了解Spring Expression Language(SpEL) Spring Expression Language(SpEL)是Spring框架中强大的表达式语言,它在运行时提供了一种灵活的方式来评估字符串表达式。SpEL的设计目标是在各种Spring配置和编程场景中提供…

亚马逊AWS考试认证系列 - Retake是考试的坚强后盾

为什么说Retake是考试的坚强后盾? 在AWS的认证考试体系里面,Retake 是一次重考的机会,允许考生在第一次未通过考试的情况下,再次免费参加考试,注意是免费的。这为考生提供了一个机会来重新准备并且免费再次进行考试。…

【数据库】Unlogged 表使用

【数据库】Unlogged 表使用 前言普通表和Unlogged 表的写性能比较普通表创建和数据插入Unlogged 表创建和数据插入比较结果 Unlogged 表崩溃和正常关闭测试Unlogged 表特点总结 前言 大神偶像在开会上提及了Unlogged 表,它的特点很不错,很适合实时数据保…

关于域名递归解析服务的问题

域名递归解析服务是互联网基础设施的重要组成部分,它允许用户通过域名来访问网站或应用程序。然而,在某些情况下,域名递归解析服务可能会出现问题,导致用户无法正常访问网站或应用程序。本文将探讨域名递归解析服务可能面临的问题…

elementPlus实现动态表格单元格合并span-method方法总结

最近在做PC端需求的时候,需要把首列中相邻的同名称单元格合并。 我看了一下elementPlus官网中的table表格,span-method可以实现单元格合并。 我们先看一下官网的例子: 合并行或列 多行或多列共用一个数据时,可以合并行或列。 …

【附代码】NumPy加速库NumExpr(大数据)

文章目录 相关文献测试电脑配置数组加减乘除数组乘方Pandas加减乘除总结 作者:小猪快跑 基础数学&计算数学,从事优化领域5年,主要研究方向:MIP求解器、整数规划、随机规划、智能优化算法 如有错误,欢迎指正。如有…

Java 学习和实践笔记(2)

今天的学习进度: 注册并下载安装好了Java 8,之后进行以下配置。 1)path 是一个常见的环境变量,它告诉系统除了在当前的目标下妹寻找此程序外,还可以到path指定的目录下找。 2)Java Home 为以后其他的软…