linux内核内存空间申请kmalloc kzalloc和vmalloc的区别

本文介绍了在内核空间中使用kmalloc(), kzalloc()和vmalloc()进行内存申请的方法,比较了它们的用途、内存特性、限制和释放函数,强调了kmalloc和vmalloc的选择依据。

转自:http://www.th7.cn/system/lin/201606/167750.shtml

我们都知道在用户空间动态申请内存用的函数是 malloc(),这个函数在各种操作系统上的使用是一致的,对应的用户空间内存释放函数是 free()。注意:动态申请的内存使用完后必须要释放,否则会造成内存泄漏,如果内存泄漏发生在内核空间,则会造成系统崩溃。
  那么,在内核空间中如何申请内存呢?一般我们会用到 kmalloc()、kzalloc()、vmalloc() 等,下面我们介绍一下这些函数的使用以及它们之间的区别。

kmalloc()

函数原型:

void *kmalloc(size_t size, gfp_t flags);

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

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

flags 的参考用法:
 |– 进程上下文,可以睡眠     GFP_KERNEL
 |– 进程上下文,不可以睡眠    GFP_ATOMIC
 |  |– 中断处理程序       GFP_ATOMIC
 |  |– 软中断          GFP_ATOMIC
 |  |– Tasklet         GFP_ATOMIC
 |– 用于DMA的内存,可以睡眠   GFP_DMA | GFP_KERNEL
 |– 用于DMA的内存,不可以睡眠  GFP_DMA |GFP_ATOMIC
  
对应的内存释放函数为:

void kfree(const void *objp);
kzalloc()

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

/** * kzalloc - allocate memory. The memory is set to zero. * @size: how many bytes of memory are required. * @flags: the type of memory to allocate (see kmalloc). */static inline void *kzalloc(size_t size, gfp_t flags){    return kmalloc(size, flags | __GFP_ZERO);}

kzalloc() 对应的内存释放函数也是 kfree()。

vmalloc()

函数原型:

void *vmalloc(unsigned long size);

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

对应的内存释放函数为:

void vfree(const void *addr);

注意:vmalloc() 和 vfree() 可以睡眠,因此不能从中断上下文调用。
  

总结

kmalloc()、kzalloc()、vmalloc() 的共同特点是:

  1. 用于申请内核空间的内存;
  2. 内存以字节为单位进行分配;
  3. 所分配的内存虚拟地址上连续;

kmalloc()、kzalloc()、vmalloc() 的区别是:

  1. kzalloc 是强制清零的 kmalloc 操作;(以下描述不区分 kmalloc 和 kzalloc)
  2. kmalloc 分配的内存大小有限制(128KB),而 vmalloc 没有限制;
  3. kmalloc 可以保证分配的内存物理地址是连续的,但是 vmalloc 不能保证;
  4. kmalloc 分配内存的过程可以是原子过程(使用 GFP_ATOMIC),而 vmalloc 分配内存时则可能产生阻塞;
  5. kmalloc 分配内存的开销小,因此 kmalloc 比 vmalloc 要快;

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

<think>我们正在讨论Linux内核内存分配函数kzallockmalloc区别及使用场景。首先,我们需要明确这两个函数的基本定义功能。 kmallocLinux内核中用于分配连续物理内存的函数,其原型为:void*kmalloc(size_t size, gfp_tflags);它分配的内存是物理地址连续的,大小至少为指定的大小,并且分配后内存的内容是未初始化的(即可能包含随机数据)。kzallockmalloc的一个变种,其原型为: void*kzalloc(size_tsize,gfp_t flags);它除了分配内存外,还会将分配的内存初始化为零。实际上,kzalloc相当于用kmalloc分配内存后,再调用memset将内存置零。因此,主要区别在于:1.初始化:kzalloc会将分配的内存初始化为0,而kmalloc不会。2.性能:由于kzalloc需要额外的清零操作,因此它比kmalloc稍慢。但在很多情况下,这种性能差异可以忽略不计,特别是当安全性要求较高时。使用场景:-当需要分配内存并确保其内容不被之前的数据污染时(例如,分配结构体内存,并且希望所有成员初始为0),应使用kzalloc。-如果分配的内存将立即被完全覆盖,或者不需要初始化,那么使用kmalloc更高效。另外,kzalloc实际上是使用kmalloc实现的,只是它使用了标志位__GFP_ZERO,该标志位要求分配的内存被清零。因此,我们也可以手动使用kmalloc并指定__GFP_ZERO标志来达到同样的效果。例如:使用kzalloc:ptr= kzalloc(size,GFP_KERNEL);等价于:ptr =kmalloc(size,GFP_KERNEL| __GFP_ZERO);但是,使用kzalloc更简洁,并且避免了手动设置标志位的麻烦。在驱动开发中,通常推荐使用kzalloc来分配结构体,因为这样可以避免未初始化成员带来的安全问题(例如,未初始化的指针可能导致内核崩溃)。而对于缓冲区等可能立即被覆盖的数据,可以使用kmalloc。另外,需要注意的是,这两个函数分配的内存都需要使用kfree来释放。下面我们通过一个简单的例子来说明:假设我们有一个结构体:struct my_struct{int a;char b;void*c;};如果我们使用kmalloc分配:structmy_struct*p= kmalloc(sizeof(struct my_struct),GFP_KERNEL);那么p指向的内存中,成员a、bc的值都是未定义的。而使用kzalloc:struct my_struct *p =kzalloc(sizeof(struct my_struct),GFP_KERNEL);则p->a为0,p->b为0,p->c为NULL。这样,在后续使用中,我们可以安全地检查p->c是否为NULL,而不会因为随机值导致误判。总结:-kzalloc=kmalloc+ memset(0)-需要初始化内存为零时用kzalloc,否则用kmalloc(并确保后续会覆盖或不需要初始化)在性能敏感的路径上,如果确定不需要清零,使用kmalloc可以避免不必要的清零开销。引用说明:[^1]:Linux内核源码中关于kmallockzalloc的实现,以及内存分配标志的定义。[^2]:Linux设备驱动开发详解(书籍)中关于内存分配的建议。生成相关问题:根据这个主题,我们可以提出以下问题:1.kzallockmalloc在内存分配失败时的行为是否相同?2.除了kzallockmallocLinux内核还有哪些内存分配函数?3.在什么情况下必须使用kmalloc而不是kzalloc?4.如何选择kmalloc的标志(如GFP_KERNEL, GFP_ATOMIC)?5. kzalloc是否会导致额外的性能开销?在哪些场景下这种开销是值得的?注意:引用标识在回答中自然添加,如上述回答中已经添加了[^1][^2]。</think>### Linux内核kzallockmalloc区别及使用场景 在Linux内核开发中,`kmalloc``kzalloc`都是动态内存分配函数,但存在关键差异: #### 1. **核心区别** - **`kmalloc`** 分配指定大小的内存块,**不初始化内存内容**(可能包含随机数据)。 函数原型:`void *kmalloc(size_t size, gfp_t flags);` 示例:`ptr = kmalloc(100, GFP_KERNEL);` - **`kzalloc`** 分配内存并**自动初始化为全零**(等效于`kmalloc + memset(0)`)。 函数原型:`void *kzalloc(size_t size, gfp_t flags);` 内部实现等价于:`kmalloc(size, flags | __GFP_ZERO);` #### 2. **性能对比** | 函数 | 初始化开销 | 速度 | 内存内容 | |----------|------------|------------|--------------| | `kmalloc` | 无 | ⚡ **更快** | 未初始化数据 | | `kzalloc` | 有清零操作 | 稍慢 | 全零 | #### 3. **典型使用场景** - **优先使用`kzalloc`当**: - 分配结构体或对象需默认零值(如`task_struct`) - 避免未初始化敏感数据(如加密密钥) - 简化代码(省去手动`memset`) ```c // 安全初始化结构体 struct device *dev = kzalloc(sizeof(*dev), GFP_KERNEL); ``` - **优先使用`kmalloc`当**: - 内存将立即被完全覆盖(如DMA缓冲区) - 性能关键路径(减少清零开销) - 分配大型非敏感缓冲区 ```c // 快速分配将被填充的缓冲区 char *buf = kmalloc(BUF_SIZE, GFP_ATOMIC); memcpy(buf, source_data, BUF_SIZE); ``` #### 4. **关键注意事项** 1. **释放方式相同**:两者均需用`kfree()`释放 2. **物理连续性**:均保证物理地址连续(适用于DMA) 3. **标志位兼容**:支持相同的`GFP_*`内存分配标志(如`GFP_KERNEL`/`GFP_ATOMIC`) 4. **大小限制**:最大分配尺寸通常为4MB(依赖`CONFIG_FRAG_ALLOC`) > **安全建议**:在驱动开发中优先使用`kzalloc`,可避免未初始化内存漏洞(如内核信息泄漏)[^1]。 --- ### 相关问题 1. `kzalloc`的零初始化在内核启动阶段是否会产生性能瓶颈? 2. 如何通过`kmalloc`手动实现等效于`kzalloc`的功能? 3. 什么场景下必须使用`GFP_ATOMIC`标志而非`GFP_KERNEL`? 4. `vmalloc`与`kmalloc`有何区别?何时应选择`vmalloc`? 5. Linux内核如何处理`kzalloc/kmalloc`的内存碎片问题? [^1]: Linux内核文档`memory-allocation.txt`强调零初始化对安全性的重要性。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值