malloc、alloc、kmalloc、kzalloc、vmalloc等的区别
关于c语言的内存分配方式:
(1) 从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。
(2) 在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
(3)从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。
linux应用程序申请的动态内存是属于在用户空间中申请内存,在内核空间中申请内存,一般我们会用到 kmalloc()、kzalloc()、vmalloc() 等
在 Linux 系统中的每个进程都有独立 4GB 内存空间,而 Linux 把这 4GB 内存空间划分为用户内存空间(0 ~ 3GB)和内核内存空间(3GB ~ 4GB),而内核内存空间由划分为直接内存映射区和动态内存映射区(vmalloc区)。
直接内存映射区从 3GB 开始到 3GB+896MB 处结束,直接内存映射区的特点就是物理地址与虚拟地址的关系为:
虚拟地址 = 物理地址 + 3GB
而动态内存映射区不能通过这种简单的关系关联,而是需要访问动态内存映射区时,由内核动态申请物理内存并且映射到动态内存映射区中。动态内存映射区在内存空间的位置:
具体的API :API解释描述void *malloc(unsigned int num_bytes)内存是匿名的malloc()分配了内存,但没有为它指定名字。然而,它却可以返回那块内存第一个字节的地址。因此,可以把那个地址赋值给一个指针变量,并使用该指针来访问那块内存。因为char代表一个字节,所以传统上曾将malloc()定义为指向char的指针类型。double * ptd;ptd = (double * ) malloc (30 * sizeof(double));这段代码请求30个double类型值的空间,并且把ptd指向该空间所在位置。注意:ptd是作为指向一个double类型值的指针声明的,而不是指向30个double类型值的数据块的指针。void *kmalloc(size_t size, gfp_t flags);void kfree(const void *objp);较常用的 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 1)最小申请的内存大小为32字节或64字节(受系统影响)2)最大申请的内存大小一般不超过128K(受系统影响)===========================static __always_inline void *kmalloc(size_t size, gfp_t flags){ if (__builtin_constant_p(size)) { //用于编译器的优化,size是不是常量 if (size > KMALLOC_MAX_CACHE_SIZE) //用于确认最大开辟空间,该值为8K //用于申请大内存,以page为粒度的申请,该函数最终调用的是alloc_pages函数,用的是伙伴系统 return kmalloc_large(size, flags);#ifndef CONFIG_SLOB if (!(flags & GFP_DMA)) { int index = kmalloc_index(size); if (!index) return ZERO_SIZE_PTR; //用于申请小内存,最后使用slab_slloc来完成 return kmem_cache_alloc_trace(kmalloc_caches[index], flags, size); }#endif } return __kmalloc(size, flags);}void *vmalloc(unsigned long size);void vfree(const void *addr);static inline void * vmalloc(unsigned long size){ return __vmalloc(size, GFP_KERNEL|__GFP_HIGHMEM, PAGE_KERNEL);}void *kzalloc(size_t size, gfp_t flags);void kfree(const void *objp);static inline void *kzalloc(size_t size, gfp_t flags){ return kmalloc(size, flags | __GFP_ZERO);}#define __GFP_ZERO ((__force gfp_t)0x8000u) /* Return zeroed page on success */因为 kzalloc() 实际上只是额外附加了 __GFP_ZERO 标志。所以它除了申请内核内存外,还会对申请到的内存内容清零。
面试的时候问这个比较多:
kmalloc()、kzalloc()、vmalloc() 的共同特点是:
kmalloc()、kzalloc()、vmalloc() 的区别是:
使用场合:
一般情况下,内存只有在要被 DMA 访问的时候才需要物理上连续,但为了性能上的考虑,内核中一般使用 kmalloc(),而只有在需要获得大块内存时才使用 vmalloc()。例如,当模块被动态加载到内核当中时,就把模块装载到由 vmalloc() 分配的内存上。对于需要对分配的内存清零操作的,可以直接利用kzalloc来申请。
参考文献:
malloc、kmalloc、kzalloc、vmalloc的区别_kzalloc和malloc区别-CSDN博客
linux内存管理之内存分配函数区别_malloc kzalloc-CSDN博客
malloc、vmalloc、kmalloc、kzalloc、mmap的区别 – CSDN文库
Linux驱动开发需要注意的点/KO大小/内存管理_linux驱动.ko 变量存放在内存里吗-CSDN博客
Linux内核vmalloc原理与实现-CSDN博客
2024最新激活全家桶教程,稳定运行到2099年,请移步至置顶文章:https://sigusoft.com/99576.html
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。 文章由激活谷谷主-小谷整理,转载请注明出处:https://sigusoft.com/93536.html