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名称用户/内核空间物理连续?大小限制单位场景描述注意点malloc/calloc/realloc/free用户空间不保证堆申请字节calloc初始化为0;realloc改变内存大小。malloc ()是C标准库函数,用于动态分配内存,它分配的内存是在进程的堆空间,可以释放,但是不能直接映射设备地址空间动态申请的内存使用完后必须要释放,否则会造成内存泄漏,如果内存泄漏发生在内核空间,则会造成系统崩溃。alloca用户空间栈申请字节向栈申请内存,因此无需释放.mmap/munmap用户空间将文件利用虚拟内存技术映射到内存中去。brk、sbrk用户空间虚拟内存到内存的映射。sbrk(0)返回program break地址,sbrk调整对的大小。malloc是用户层的内存分配函数,最终会通过brk() 和nmap()进行系统调用vmalloc/vfree内核空间虚拟连续,物理不一定连续vmalloc区大小无限制页VMALLOC区域可能睡眠,不能从中断上下文中调用,或其他不允许阻塞情况下调用。VMALLOC区域vmalloc_start~vmalloc_end之间,vmalloc比kmalloc慢,适用于分配大内存。vmalloc() 函数则会在虚拟内存空间给出一块连续的内存区,但这片连续的虚拟内存在物理内存中并不一定连续。由于 vmalloc() 没有保证申请到的是连续的物理内存,因此对申请的内存大小没有限制,如果需要申请较大的内存空间就需要用此函数了。vmalloc() 和 vfree() 可以睡眠,因此不能从中断上下文调用。如果要申请大块的内存就可以用vmallockmalloc/kcalloc/krealloc/kfree内核空间 kmalloc是基于slab分配机制实现的申请的内存位于物理内存映射区域,而且在物理上也是连续的64B-4MB(随slab而变)2^order字节Normal区域Normal区域大小有限,不如vmalloc/malloc大。最大/小值由KMALLOC_MIN_SIZE/KMALLOC_SHIFT_MAX,对应64B/4MB。从/proc/slabinfo中的kmalloc-xxxx中分配,建立在kmem_cache_create基础之上。在Linux内核中, kmalloc能够分配的最大连续内存为2的(MAX_ORDER-1)次方个page(参见alloc_pages函数, "if (unlikely(order >= MAX_ORDER)) return NULL;"), page的大小一般是4K bytes, MAX_ORDER缺省定义为11, 所以如果不修改内核, kmalloc能够分配的最大连续内存一般是4M bytes。kmem_cache_create内核空间slab物理连续64B-4MB字节大小,需对齐Normal区域便于固定大小数据的频繁分配和释放,分配时从缓存池中地址,释放时也不一定真正释放内存。通过slab进行管理。__get_free_page/__get_free_pages内核空间物理连续4MB(1024页)页Normal区域__get_free_pages基于alloc_pages,申请的大小是一整页,但是限定不能使用HIGHMEM。和kmalloc最终调用实现是相同的,只不过在调用最终函数时所传的flag不同alloc_page/alloc_pages/free_pages内核空间物理连续4MB页Normal/Vmalloc都可CONFIG_FORCE_MAX_ZONEORDER定义了最大页面数2^11,一次能分配到的最大页面数是1024。kzalloc() / kfree()kzalloc() 函数与 kmalloc() 非常相似,参数及返回值是一样的,可以说是前者是后者的一个变种,因为 kzalloc() 实际上只是额外附加了 __GFP_ZERO 标志。所以它除了申请内核内存外,还会对申请到的内存内容清零。z–>zero,就是清零的意思。
具体的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