当前位置: 首页 > article >正文

Linux驱动编程 - kmalloc、vmalloc区别

目录

 

前言:

1、区别

2、使用差异

一、kmalloc、kzalloc、kfree

1、动态申请

1.1 kmalloc()

1.2 kzalloc()

2、内存释放

3、示例

二、vmalloc、vzalloc、vfree

1、动态申请

1.1 vmalloc()

1.2 vzalloc()

2、内存释放

3、示例


前言:


        Linux内核空间一般使用 kmalloc()、kzalloc()、vmalloc() 、vzalloc() 动态申请内存。下面记录如何使用。


1、区别


  • vmalloc从高端内存开始分配,当内存不够时才分配低端内存。kmalloc从低端内存开始分配;
  • vmalloc和kmalloc分配的虚拟地址都是连续的,但是vmalloc分配的物理地址一般不连续,kmalloc分配的物理地址连续
  • vmalloc分配的一般是大块的内存,而kmalloc一般分配的是小块内存(不超过128k);
函数位置特性大小限制
kmalloc低端内存(线性映射)区域物理地址虚拟地址均连续不能超过128K
kzalloc低端内存(线性映射)区域物理地址虚拟地址均连续不能超过128K
vmalloc高端内存(动态映射)区域虚拟地址连续,物理地址不一定连续无限制
vzalloc高端内存(动态映射)区域虚拟地址连续,物理地址不一定连续无限制

2、使用差异


  • kmalloc 分配内存的过程可以是原子过程(使用 GFP_ATOMIC),而 vmalloc 分配内存时则可能产生阻塞;
  • kmalloc 分配内存的开销小,因此 kmalloc 比 vmalloc 要快;

注意:一般情况下,内存只有在要被 DMA 访问的时候才需要物理上连续,但为了性能上的考虑,内核中一般使用 kmalloc(),而只有在需要获得大块内存时才使用 vmalloc()。例如,当模块被动态加载到内核当中时,就把模块装载到由 vmalloc() 分配的内存上。

一、kmalloc、kzalloc、kfree


1、动态申请


1.1 kmalloc()

/* include/linux/slab.h */
void *kmalloc(size_t size, gfp_t flags);

功能: kmalloc() 申请的内存位于物理内存映射(低端内存)区域,而且在物理上也是连续的,它们与真实的物理地址只有一个固定的偏移,因为存在较简单的转换关系,所以对申请的内存大小有限制,不能超过128KB

参数:

  • size:申请内存大小
  • flags:分配标志

       (1)flags 常用值

GFP_ATOMIC分配内存的过程是一个原子过程,分配内存的过程不会被(高优先级进程或中断)打断
GFP_KERNEL正常分配内存
GFP_DMA给 DMA 控制器分配内存,需要使用该标志(DMA要求分配虚拟地址和物理地址连续)

        (2)flags 用法

​ |– 进程上下文,可以睡眠     GFP_KERNEL
 |– 进程上下文,不可以睡眠    GFP_ATOMIC
 |  |– 中断处理程序       GFP_ATOMIC
 |  |– 软中断          GFP_ATOMIC
 |  |– Tasklet         GFP_ATOMIC
 |– 用于DMA的内存,可以睡眠   GFP_DMA | GFP_KERNEL
 |– 用于DMA的内存,不可以睡眠  GFP_DMA | GFP_ATOMIC

        如果进程上下文允许睡眠情况下尽量用 GFP_KERNEL, 如果进程上下文禁止休眠的话(如中断,taskletd等)必须用 GFP_ATOMIC

返回值:

  • 非NULL:申请到的内存虚拟地址(指向一块物理上连续的内存区域);
  • NULL:申请失败;

1.2 kzalloc()

kzalloc() 函数与 kmalloc() 非常相似,参数及返回值是一样的。kzalloc() 实际上只是额外附加了__GFP_ZERO标志。所以它除了申请内核内存外,还会对申请到的内存内容清零。

/* include/linux/slab.h */
static inline void *kzalloc(size_t size, gfp_t flags)
{
	return kmalloc(size, flags | __GFP_ZERO);
}

2、内存释放


kmalloc() 和 kzalloc() 的内存释放函数都是 kfree()

/* mm/slob.c */
void kfree(const void *objp);

参数:

  • objp:kmalloc() 和 kzalloc() 申请的内存首地址

3、示例


/* 申请内存 */
pBuffer = kmalloc(1024, GFP_KERNEL);
if (!pBuffer) {
    printk(KERN_ERR "kmalloc failed\n");
    return -1;
}


/* 释放内存 */
kfree(pBuffer);

二、vmalloc、vzalloc、vfree


注意:vmalloc和vfree可以休眠,因此中断上下文禁止使用

1、动态申请


1.1 vmalloc()

/* mm/vmalloc.c */
void *vmalloc(unsigned long size)
{
	return __vmalloc_node_flags(size, NUMA_NO_NODE,
				    GFP_KERNEL);
}

功能:vmalloc() 函数则会在虚拟内存(高端内存)区域给出一块连续的内存区,但这片连续的虚拟内存在物理内存中并不一定连续。由于 vmalloc() 没有保证申请到的是连续的物理内存,因此对申请的内存大小没有限制,如果需要申请较大的内存空间就需要用此函数了。

参数:

  • size:申请内存的大小

返回值:

  • 非NULL:申请到的内存的虚拟地址;
  • NULL:申请失败;

1.2 vzalloc()

vzalloc比vmalloc步骤多了一步,将申请的逻辑地址连续的内存数据置为0

/* mm/vmalloc.c */
void *vzalloc(unsigned long size)
{
  	return __vmalloc_node_flags(size, NUMA_NO_NODE,
  				GFP_KERNEL | __GFP_ZERO);
}

2、内存释放


vmalloc() 和 vzalloc() 的内存释放函数都是 vfree()

void vfree(const void *addr);

3、示例


/* 申请内存 */
pBuffer = vmalloc(1024);
if (!pBuffer ) {
    printk(KERN_ERR "vmalloc failed\n");
    return -1;
}

/* 释放内存 */
vfree(pBuffer);


http://www.kler.cn/a/404485.html

相关文章:

  • 案例精选 | 某知名教育集团基于安全运营平台的全域威胁溯源实践
  • 达索系统亮相第三十一届中国汽车工程学会年会暨展览会
  • 卫生间门选择单包套还是双包套好?
  • 【实用数据】上市公司数字化转型双重差分准自然实验数据(2007-2022年)
  • 【 模型】 开源图像模型Stable Diffusion入门手册
  • C++中的移动语义
  • 多线程中Callable和Runnable的对比
  • 力扣 LeetCode 106. 从中序与后序遍历序列构造二叉树(Day9:二叉树)
  • MySQL45讲 第二十八讲 读写分离有哪些坑?——阅读总结
  • 第 24 章 -Golang 性能优化
  • 【C++入门(一)】半小时入门C++开发(深入理解new+List+范围for+可变参数)
  • 【GPTs】Front-end Expert:助力前端开发的智能工具
  • 设计模式之 组合模式
  • PCIe总线设计
  • Java中的TreeSet集合解析
  • 计算机毕设-基于springboot的多彩吉安红色旅游网站的设计与实现(附源码+lw+ppt+开题报告)
  • JMeter 性能测试计划深度解析:构建与配置的树形结构指南
  • k8s1.30.0高可用集群部署
  • 04-转录组下游分析-标准化、聚类、差异分析
  • C++真题实战(一)[卡片问题]
  • 动静态库:选择与应用的全方位指南
  • .NET开源实时应用监控系统:WatchDog
  • 《C++20 图形界面程序:速度与渲染效率的双重优化秘籍》
  • STM32学习笔记----三极管和MOS管的区别
  • 【人工智能】深度学习入门:用TensorFlow实现多层感知器(MLP)模型
  • 使用 IntelliJ IDEA 编写 Spark 应用程序(Scala + Maven)