array(2) { ["docs"]=> array(10) { [0]=> array(10) { ["id"]=> string(3) "428" ["text"]=> string(77) "Visual Studio 2017 单独启动MSDN帮助(Microsoft Help Viewer)的方法" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(8) "DonetRen" ["tagsname"]=> string(55) "Visual Studio 2017|MSDN帮助|C#程序|.NET|Help Viewer" ["tagsid"]=> string(23) "[401,402,403,"300",404]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400964" ["_id"]=> string(3) "428" } [1]=> array(10) { ["id"]=> string(3) "427" ["text"]=> string(42) "npm -v;报错 cannot find module "wrapp"" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "zzty" ["tagsname"]=> string(50) "node.js|npm|cannot find module "wrapp“|node" ["tagsid"]=> string(19) "[398,"239",399,400]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400760" ["_id"]=> string(3) "427" } [2]=> array(10) { ["id"]=> string(3) "426" ["text"]=> string(54) "说说css中pt、px、em、rem都扮演了什么角色" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(12) "zhengqiaoyin" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400640" ["_id"]=> string(3) "426" } [3]=> array(10) { ["id"]=> string(3) "425" ["text"]=> string(83) "深入学习JS执行--创建执行上下文(变量对象,作用域链,this)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "Ry-yuan" ["tagsname"]=> string(33) "Javascript|Javascript执行过程" ["tagsid"]=> string(13) "["169","191"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511399901" ["_id"]=> string(3) "425" } [4]=> array(10) { ["id"]=> string(3) "424" ["text"]=> string(30) "C# 排序技术研究与对比" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "vveiliang" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(8) ".Net Dev" ["catesid"]=> string(5) "[199]" ["createtime"]=> string(10) "1511399150" ["_id"]=> string(3) "424" } [5]=> array(10) { ["id"]=> string(3) "423" ["text"]=> string(72) "【算法】小白的算法笔记:快速排序算法的编码和优化" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "penghuwan" ["tagsname"]=> string(6) "算法" ["tagsid"]=> string(7) "["344"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511398109" ["_id"]=> string(3) "423" } [6]=> array(10) { ["id"]=> string(3) "422" ["text"]=> string(64) "JavaScript数据可视化编程学习(二)Flotr2,雷达图" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "chengxs" ["tagsname"]=> string(28) "数据可视化|前端学习" ["tagsid"]=> string(9) "[396,397]" ["catesname"]=> string(18) "前端基本知识" ["catesid"]=> string(5) "[198]" ["createtime"]=> string(10) "1511397800" ["_id"]=> string(3) "422" } [7]=> array(10) { ["id"]=> string(3) "421" ["text"]=> string(36) "C#表达式目录树(Expression)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "wwym" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(4) ".NET" ["catesid"]=> string(7) "["119"]" ["createtime"]=> string(10) "1511397474" ["_id"]=> string(3) "421" } [8]=> array(10) { ["id"]=> string(3) "420" ["text"]=> string(47) "数据结构 队列_队列实例:事件处理" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "idreamo" ["tagsname"]=> string(40) "C语言|数据结构|队列|事件处理" ["tagsid"]=> string(23) "["246","247","248",395]" ["catesname"]=> string(12) "数据结构" ["catesid"]=> string(7) "["133"]" ["createtime"]=> string(10) "1511397279" ["_id"]=> string(3) "420" } [9]=> array(10) { ["id"]=> string(3) "419" ["text"]=> string(47) "久等了,博客园官方Android客户端发布" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(3) "cmt" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511396549" ["_id"]=> string(3) "419" } } ["count"]=> int(200) } 222 LINUX内核内存管理kmalloc,vmalloc - 爱码网

https://blog.csdn.net/wh8_2011/article/details/52946974


一.kmalloc与vmallco

    在设备驱动程序或者内核模块中动态开辟内存,不是用malloc,而是kmalloc ,vmalloc,释放内存用的是kfree,vfree,kmalloc函数返回的是虚拟地址(线性地址). kmalloc特殊之处在于它分配的内存是物理上连续的,这对于要进行DMA的设备十分重要. 而用vmalloc分配的内存只是线性地址连续,物理地址不一定连续,不能直接用于DMA。vmalloc函数的工作方式类似于kmalloc,只不过前者分配的内存虚拟地址是连续的,而物理地址则无需连 续。通过vmalloc获得的页必须一个一个地进行映射,效率不高, 因此,只在不得已(一般是为了获得大块内存)时使用。vmalloc函数返回一个指针,指向逻辑上连续的一块内存区,其大小至少为size。在发生错误 时,函数返回NULL。vmalloc可能睡眠,因此,不能从中断上下文中进行调用,也不能从其它不允许阻塞的情况下调用。要释放通过vmalloc所获 得的内存,应使用vfree函数

    vmalloc和kmalloc的分配内存的特点大概如下:

        LINUX内核内存管理kmalloc,vmalloc

  区别大概可总结为:

      1,vmalloc分配的一般为高端内存,只有当内存不够的时候才分配低端内存;kmallco从低端内存分配。

      2,vmalloc分配的物理地址一般不连续,而kmalloc分配的地址连续,两者分配的虚拟地址都是连续的;

      3,vmalloc分配的一般为大块内存,而kmaooc一般分配的为小块内存,(一般不超过128k);

   

二.DMA工作

    为了减少CPU对快速设备入出的操作,可以通过把这 批数据的传输过程交由一块专用的接口卡(DMA接口)来控制,让DMA卡代替CPU控制在快速设备与主存储器之间直接传输数据,其大概工作的机制是在DMA模式下,CPU只须向DMA控制器下达指令,让DMA控制器来处理数据的传送,数据传送完毕再把信息反馈给CPU,这样就很大程度上减轻了 CPU资源占有率。

    工作示意图大概如下:

            LINUX内核内存管理kmalloc,vmalloc

 

    以下是测试的代码:

          

LINUX内核内存管理kmalloc,vmalloc
  1 #include <linux/init.h>
  2 #include <linux/thread_info.h>
  3 #include <linux/module.h>
  4 #include <linux/sched.h>
  5 #include <linux/errno.h>
  6 #include <linux/kernel.h>
  7 #include <linux/module.h>
  8 #include <linux/slab.h>
  9 #include <linux/input.h>
 10 #include <linux/init.h>
 11 #include <linux/serio.h>
 12 #include <linux/delay.h>
 13 #include <linux/clk.h>
 14 #include <linux/miscdevice.h>
 15 #include <linux/io.h>
 16 #include <linux/ioport.h>
 17 #include <linux/vmalloc.h>
 18 #include <linux/dma-mapping.h>
 19 #include <linux/export.h>
 20 #include <linux/gfp.h>
 21 
 22 #include <asm/dma-mapping.h>
 23 #include <asm/uaccess.h>
 24 
 25 #include <linux/gpio.h>
 26 #include <mach/gpio.h>
 27 #include <plat/gpio-cfg.h>
 28 
 29 MODULE_LICENSE("GPL");
 30 MODULE_AUTHOR("bunfly");
 31 
 32 
 33 unsigned long vmalloc_to_pfn(const void *vmalloc_addr);
 34 int test_init()
 35 {
 36     int ret = 0;
 37     unsigned char *vmalloc_virt, *normal_virt, *phys;
 38     unsigned long pfn;
 39 
 40     printk("KERNEL SPACE: init\n");
 41 
 42     printk("KERNEL SPACE: read from d0003000: %s\n", 0xd0003000);
 43     //读出d0003000虚拟地址里面的数据
 44 
 45     normal_virt = kmalloc(40, GFP_KERNEL);
 46     //kmalloc分配一段虚拟地址,大小,睡眠不可中断
 47 
 48     phys = virt_to_phys(normal_virt);
 49     printk("KMAKLLOC: kmalloc virt: %p <==> phys: %p\n", normal_virt, phys);
 50 
 51     kfree(normal_virt);
 52 
 53     //分配页
 54     //--------------------------------------
 55     vmalloc_virt = vmalloc(500);
 56     //vmalloc分配内存
 57 
 58     pfn = vmalloc_to_pfn(vmalloc_virt);
 59     //页分配
 60     phys = (pfn << 12) | ((unsigned long)vmalloc_virt & 0xfff);
 61     //将页地址转换成物理地址
 62     normal_virt = phys_to_virt(phys);
 63     //再将物理地址转换成虚拟地址
 64     printk("VMALLOC: vmalloc_virt = %p, normal_virt = %p\n", vmalloc_virt, normal_virt);
 65 
 66     //dma分配
 67     normal_virt = dma_alloc_coherent(NULL, 1024, &phys, GFP_KERNEL);
 68     printk("DMA: vmalloc_virt = %p, normal_virt = %p\n", vmalloc_virt,phys);
 69     dma_free_coherent(NULL, 1024, normal_virt, phys);
 70 
 71     vfree(vmalloc_virt);
 72     return 0;
 73 }
 74 
 75 void test_exit()
 76 {
 77     printk("KERNEL SPACE: exit\n");
 78 }
 79 
 80 module_init(test_init);
 81 module_exit(test_exit);
 82 
~                                                                                                                                                                                                                                                                                                                                                                                                                                  
~                                                                                                                                                                                                                                                                                                                                                                                                                                  
~  
LINUX内核内存管理kmalloc,vmalloc

      首先,在50003000地址放入数据,然后在d0003000的物理地址中读出数据:

      LINUX内核内存管理kmalloc,vmalloc

      查看50003000地址中的数据:

      LINUX内核内存管理kmalloc,vmalloc

 

      启动板子,插入模块,运行结果:

      LINUX内核内存管理kmalloc,vmalloc 

      可以看到kmalloc的物理地址是低端内存的,(从40000000开始),而vmalloc分配的物理地址是高端内存,而通过    DMA内存的也是低端一点的。

  补充说明:kmalloc函数原型:

   static __always_inline void *kmalloc(size_t size, gfp_t flags)
        其中falgs有

      LINUX内核内存管理kmalloc,vmalloc

      主要的要分配两种:一般都是

            GFP_KERNLE;内核使用内存--------可以睡眠

            GFP_USER;   用户空间内存;

            GFP_ATOMIC;  原子分配  ---------不可以睡眠

    内核编程的法则:

        中断上下文不可以睡眠(可以用is_inetrruput()函数查看是否是中断处理调用函数,返回1为真)

相关文章: