Linux设备驱动程序 之 kmalloc
原型
kmalloc的原型如下:
void *kmalloc(size_t size, gfp_t flags)
第一个参数是要分配的块的大小,第二个参数是分片标志;
flags标志
最常用的标志是GFP_KERNEL,表示内存分配(最终总是调用get_free_page来实现实际的分配,这就是GFP_前缀的由来)是代表在内核空间的进程执行的;换句话说,这意味着调用它的函数正代表某个进程执行系统调用;使用GFP_KERNEL允许在kmalloc在空闲内存较少的时候把当前进程转入休眠以等待一个页面;因此,使用GFP_KERNEL分配内存的函数必须是可重入的;在当前进程休眠时,内核会采取适当的行动,或者把缓冲区的内容刷到硬盘上,或者从搞一个用户进程换出内存,已获得一个内存页面;
GFP_KERNEL分配标志并不是始终适用,有时kmalloc是在进程上下文之外被调用的,例如中断处理程序,tasklet以及内核定时器中调用;这种情况下current进程就不该休眠,驱动程序应该换用GFP_ATOMIC标志;内核通常会为原子性的分配预留一些空闲页面;使用GFP__ATOMIC标志时,kmalloc甚至可以用掉最后一个空闲页面;不过如果连最后一页都没有了,分配就返回失败;
除了GFP_KERNEL和GFP_ATOMIC外,还有一些其他标志可用于替换或者补充这两个标志,不过这两个标志已经可以满足大多数驱动程序的需要了;
下面罗列这些标记:
GFP_ATOMIC-在中断处理程序或者其他运行与进程上下文之外的代码中分配内存,不能休眠;
GFP_KERNEL-内核内存的通常分配方法,可能引起休眠;
GFP_USER-为用户空间页分配内存,可能会休眠;
GFP_HIGHUSER-类似GFP_USER,不过如果有高端内存的话,就从那里分配;
GFP_NOIO GFP_NOFS-这两个标志类似GFP_KERNEL,但是为内核分配内存的工作方式添加了一些限制,具有GFP_NOFS标志的分配不允许执行任何文件系统调用,而GFP_NOIO禁止任何IO的初始化;这两个标志主要在文件系统和虚拟内存代码中使用,这项代码中的分配内存可休眠,但不应该发生递归的文件系统调用;
上面列出的分配标志可以和下面的标志“或”起来使用;下面这些标志控制如何进行分配:
__GFP_DMA-标志请求分配发生在可进行DMA的内存区段中;
__GFP_HIGHMEM-表明要分配的内存可位于高端内存;
__GFP_COLD-通常,内存分配器会试图返回缓存热页面,即可在处理器缓存中找到的页面;相反,这个标志请求尚未使用的冷页面;对用于DMA读取的页面分配,可以使用这个标志,因为这种情况下,页面存在于处理器缓存中没有多大帮助;
__GFP_NOWARN-该标志很少使用;它可以避免内核在无法满足分配请求的时候产生经过;
__GFP_HIGH-该标志标记了一个高优先级的请求,它允许为紧急状况而消耗有内核保留的最后一个页面;
__GFP_REPEAT、__GFP_NOFAIL、__GFP_NORETRY-上述标志告诉分配器在满足分配请求而遇到困难时应该采取何种行动;__GFP_REPEAT表示努力再尝试一次,它会重新尝试分配,当仍有可能失败;__GFP_NOFAIL标志告诉分配器始终不返回失败,它会努力满足分配请求;不鼓励使用这个标志;__GFP_NORETRY告诉分配器,如果请求的内存不可获得,就立即返回;
内存区段
__GFP_DMA和__GFP_HIGHMEM的使用与平台相关,尽管在所有平台上都可以使用这两个标志;
Linux内核把内存分成三个区段:可用于DMA的内存,常规内存以及高端内存;通常的内存分配都放生在常规内存区,但通过设置上面的标志可以把请求在其他区段中分配;其思路是每种计算平台都必须知道如何把自己特定的内存范围归类到这三个区段中,而不是认为所有的RAM都一样;
可用于DMA的内存是指存在于特别地址范围内的内存,外设可以利用这些内存执行DMA访问;在大多数健全的系统上,所有内存都位于这一区段;在x86平台上,DMA区段是RAM的前16MB;PCI设备无此限制;
高端内存是32位平台为了访问大量的内存而存在的一种机制;如果不首先完成一些特殊的映射,我们就无法从内核中直接访问这些内存,因此通常较难处理;但是,如果驱动程序要使用大量的内存,那么在能够使用高端内存的大系统上可以工作的更好;
当一个页面为了满足kmalloc的要求被分配时,内核会创建一个内存区段的列表以供搜索;如果指定了__GFP_DMA标志,则只有DMA区段会被搜索;如果低端地址上没有可用内存,就会分配失败;如果没有指定特定的标志,则常规区段和DMA区段都会被搜索;而如果设置了__GFP_HIGHMEM标志,则所有三区段都会被搜索以及获取一个空闲页面,然而要注意的是,kmalloc不能分配高端内存;
size参数
内核负责管理系统物理内存,物理内存只能按页面进行分配;其结果是kmalloc和典型的用户空间的malloc在实现上有很大的差别;简单的基于堆的分配技术会遇到麻烦,因为页面编辑的处理成为一个很棘手的问题;因此内核使用了特殊的基于页的分配技术,以及最佳地利用系统RAM;
Linux处理内存分配的方法是,创建一系列的内存池对象,每个池中的内存块大小是固定一致的;处理分配请求时,就直接在包含有足够大的内存块的池中传递一个整块请求者;
驱动程序开发应该牢记的就是内核值分配一些预定义的,固定大小的字节数组;如果申请任意数量的内存,那么得到的很可能会多一些,最多会到申请数量的两倍;另外,kmalloc能处理的最小的内存块是32或者64,到底是哪个则取决于当前体系结构使用的页面大小;
对kmalloc能够分配的内存块的大小,存在一个上限;这个限制随着体系架构的不同以及内存配置选项的不同而变化;如果希望代码有完整的可移植性,则不应该分配大于128K的内存;但是,如果希望获得多余几千字节的内存,则最好是用除kmalloc之外的内存获取方法;
Linux设备驱动程序 之 kmalloc的更多相关文章
- 【转】linux设备驱动程序中的阻塞机制
原文网址:http://www.cnblogs.com/geneil/archive/2011/12/04/2275272.html 阻塞与非阻塞是设备访问的两种方式.在写阻塞与非阻塞的驱动程序时,经 ...
- Linux设备驱动程序学习之分配内存
内核为设备驱动提供了一个统一的内存管理接口,所以模块无需涉及分段和分页等问题. 我已经在第一个scull模块中使用了 kmalloc 和 kfree 来分配和释放内存空间. kmalloc 函数内幕 ...
- linux设备驱动程序该添加哪些头文件以及驱动常用头文件介绍(转)
原文链接:http://blog.chinaunix.net/uid-22609852-id-3506475.html 驱动常用头文件介绍 #include <linux/***.h> 是 ...
- Linux设备驱动程序 第三版 读书笔记(一)
Linux设备驱动程序 第三版 读书笔记(一) Bob Zhang 2017.08.25 编写基本的Hello World模块 #include <linux/init.h> #inclu ...
- 教你写Linux设备驱动程序:一个简短的教程
教你写Linux设备驱动程序:一个简短的教程 http://blog.chinaunix.net/uid-20799298-id-99675.html
- linux设备驱动程序_hello word 模块编译各种问题集锦
在看楼经典书籍<linux设备驱动程序>后,第一个程序就是编写一个hello word 模块. 原以为非常easy,真正弄起来,发现问题不少啊.前两天编过一次,因为没有记录,今天看的时候又 ...
- Linux设备驱动程序学习----1.设备驱动程序简介
设备驱动程序简介 更多内容请参考Linux设备驱动程序学习----目录 1. 简介 Linux系统的优点是,系统内部实现细节对所有人都是公开的.Linux内核由大量复杂的代码组成,设备驱动程序可以 ...
- Linux设备驱动程序学习----2.内核模块与应用程序的对比
内核模块与应用程序的对比 更多内容请参考Linux设备驱动程序学习----目录 1. 内核模块与应用程序的对比 内核模块和应用程序之间的不同之处: 大多数中小规模的应用程序是从头到尾执行单个任务,而模 ...
- Linux设备驱动程序学习----3.模块的编译和装载
模块的编译和装载 更多内容请参考Linux设备驱动程序学习----目录 1. 设置测试系统 第1步,要先从kernel.org的镜像网站上获取一个主线内核,并安装到自己的系统中,因为学习驱动程序的编写 ...
随机推荐
- meta标签常见浏览器设置
一.如何让双核浏览器默认选择 WebKit 内核渲染自己开发的网页 我们可以使用标签来指定适合自己网站的渲染内核名称,当双核浏览器访问本网页时,就会根据我们的指示,选择我们指定的渲染内核来处理网页.若 ...
- React中setState如何修改深层对象?
在React中经常会使用到setState,因为在react生态中,state就是一切.在开发过程中,时长会在state中遇到一些比较复杂的数据结构,类似下面这样的: 这时需要我们修改list中obj ...
- 一步一步教你实现iOS音频频谱动画(二)
如果你想先看看最终效果再决定看不看文章 -> bilibili 示例代码下载 第一篇:一步一步教你实现iOS音频频谱动画(一) 本文是系列文章中的第二篇,上篇讲述了音频播放和频谱数据计算,本篇讲 ...
- 使用RevitNet操作多个版本的Revit
在Revit二次开发中,如果只是简单的从模型中提取数据或不需要界面对Revit进行修改,我们一般使用RevitNet. 如果对RevitNet不熟悉的,请参考:RevitAPI进阶之独立进程内读取.写 ...
- ORA-3136 问题处理
Alert 日志报错: Wed May :: *********************************************************************** Fatal ...
- Jupyter Notebook 插件安装
刚才安装notebook插件jupyter_contrib_nbextensions,搜了很多教程都没有作用.直到用了这个命令,一行解决. pip install jupyter_contrib_nb ...
- maven jar 包不在项目中
maven update project maven build
- 视觉SLAM关键方法总结
点"计算机视觉life"关注,置顶更快接收消息! 最近在做基于激光信息的机器人行人跟踪发现如果单独利用激光信息很难完成机器人对行人的识别.跟踪等功能,因此考虑与视觉融合的方法,这样 ...
- 2BIT
bit是比特,是英文 binary digit的缩写.而Byte是字节又叫bait. bit是表示信息的最小单位,是二进制数的一位包含的信息或2个选项中特别指定1个的需要信息量.一般来说,n比特的信息 ...
- [ 转载 ] vue.js面试题一
转载自:https://www.cnblogs.com/aimeeblogs/p/9501490.html 如有侵权 联系删除 Vue.js面试题整理 一.什么是MVVM? MVVM是Model-Vi ...