原型

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的更多相关文章

  1. 【转】linux设备驱动程序中的阻塞机制

    原文网址:http://www.cnblogs.com/geneil/archive/2011/12/04/2275272.html 阻塞与非阻塞是设备访问的两种方式.在写阻塞与非阻塞的驱动程序时,经 ...

  2. Linux设备驱动程序学习之分配内存

    内核为设备驱动提供了一个统一的内存管理接口,所以模块无需涉及分段和分页等问题. 我已经在第一个scull模块中使用了 kmalloc 和 kfree 来分配和释放内存空间. kmalloc 函数内幕 ...

  3. linux设备驱动程序该添加哪些头文件以及驱动常用头文件介绍(转)

    原文链接:http://blog.chinaunix.net/uid-22609852-id-3506475.html 驱动常用头文件介绍 #include <linux/***.h> 是 ...

  4. Linux设备驱动程序 第三版 读书笔记(一)

    Linux设备驱动程序 第三版 读书笔记(一) Bob Zhang 2017.08.25 编写基本的Hello World模块 #include <linux/init.h> #inclu ...

  5. 教你写Linux设备驱动程序:一个简短的教程

    教你写Linux设备驱动程序:一个简短的教程 http://blog.chinaunix.net/uid-20799298-id-99675.html

  6. linux设备驱动程序_hello word 模块编译各种问题集锦

    在看楼经典书籍<linux设备驱动程序>后,第一个程序就是编写一个hello word 模块. 原以为非常easy,真正弄起来,发现问题不少啊.前两天编过一次,因为没有记录,今天看的时候又 ...

  7. Linux设备驱动程序学习----1.设备驱动程序简介

    设备驱动程序简介 更多内容请参考Linux设备驱动程序学习----目录 1. 简介   Linux系统的优点是,系统内部实现细节对所有人都是公开的.Linux内核由大量复杂的代码组成,设备驱动程序可以 ...

  8. Linux设备驱动程序学习----2.内核模块与应用程序的对比

    内核模块与应用程序的对比 更多内容请参考Linux设备驱动程序学习----目录 1. 内核模块与应用程序的对比 内核模块和应用程序之间的不同之处: 大多数中小规模的应用程序是从头到尾执行单个任务,而模 ...

  9. Linux设备驱动程序学习----3.模块的编译和装载

    模块的编译和装载 更多内容请参考Linux设备驱动程序学习----目录 1. 设置测试系统 第1步,要先从kernel.org的镜像网站上获取一个主线内核,并安装到自己的系统中,因为学习驱动程序的编写 ...

随机推荐

  1. JAVA文件IO总结

    文件流的操作有两种:字节流.字符流 字节流:FileInputStream,FileInputStream 字符流:InputStreamReader,OutputStreamReader 这两种流对 ...

  2. springboot启动流程(四)application配置文件加载过程

    所有文章 https://www.cnblogs.com/lay2017/p/11478237.html 触发监听器加载配置文件 在上一篇文章中,我们看到了Environment对象的创建方法.同时也 ...

  3. swiper按钮点击无效及控制器无效问题

    点击箭头图片切换的同时,下面小图标也会随着切换,同理下面小图标切换时,上面也随着滚动. 示例代码如下: <!-- Swiper --> <div class="swiper ...

  4. Computer Vision_33_SIFT:SIFTflow Dense Correspondence across Scenes and its Applications——2011

    此部分是计算机视觉部分,主要侧重在底层特征提取,视频分析,跟踪,目标检测和识别方面等方面.对于自己不太熟悉的领域比如摄像机标定和立体视觉,仅仅列出上google上引用次数比较多的文献.有一些刚刚出版的 ...

  5. C和指针--命令行参数

    1.命令行参数 C程序的main函数具有两个形参,第1个通常称为argc,它表示命令行参数的数目.第2个称为argv,它指向一组参数值.由于参数的数目并没有内在的限制,所以argv指向这组参数值(本质 ...

  6. 玩深度学习选哪块英伟达 GPU?有性价比排名还不够!

    本文來源地址:https://www.leiphone.com/news/201705/uo3MgYrFxgdyTRGR.html 与“传统” AI 算法相比,深度学习(DL)的计算性能要求,可以说完 ...

  7. JDK源码那些事儿之HashMap.TreeNode

    前面几篇文章已经讲解过HashMap内部实现以及红黑树的基础知识,今天这篇文章就讲解之前HashMap中未讲解的红黑树操作部分,如果没了解红黑树,请去阅读前面的两篇文章,能更好的理解本章所讲解的红黑树 ...

  8. Property or method "openPageOffice" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by

    Property or method "openPageOffice" is not defined on the instance but referenced during r ...

  9. harbor1.9.0 仓库的搭建

    配置及文中的xxx 为你自己的配置信息   1.创建目录   mkdir -p /data/soft cd /data/soft   2.安装docker-composer     2.1官方安装 c ...

  10. Reflect对象

    一.Reflect对象基础 Reflect对象是ES6出现的新的API,用于操作对象内部的方法. 特点: 1. 对于操作有明确的返回结果.如返回布尔值表示操作成功与否 2. 和Proxy的拦截方法一一 ...