Linux通过一系列高效的内存分配函数来满足不同场景下的内存需求
无论是用户空间还是内核空间,Linux都提供了多种内存分配函数,确保内存资源能够得到合理的利用
本文将详细介绍Linux中的内存分配函数,帮助读者更好地理解Linux内存管理机制
用户空间内存分配函数 在用户空间中,内存分配主要通过标准C库函数实现
这些函数包括`malloc`、`calloc`、`realloc`和`alloca`等
1.malloc函数 `malloc`函数用于在堆区分配一块指定大小的内存空间
其原型为`- void malloc(size_t size)`
如果分配成功,`malloc`返回一个指向分配内存的指针;否则,返回`NULL`
`malloc`函数不会初始化分配的内存区域,因此分配的内存中可能包含垃圾数据
2.calloc函数 `calloc`函数分配并初始化一块连续的内存空间
其原型为`- void calloc(size_t num, size_tsize)`
`calloc`会分配`num`个大小为`size`的对象,并将所有字节初始化为0
这使得`calloc`非常适合用于需要初始化为零的数据结构
3.realloc函数 `realloc`函数用于改变之前通过`malloc`或`calloc`等函数分配的内存块的大小
其原型为`- void realloc(void ptr, size_t new_size)`
`realloc`可以扩大或缩小已分配的内存区域
如果内存无法重新分配,`realloc`返回`NULL`,原有的内存区域保持不变
4.alloca函数 `alloca`函数是一个非标准库函数,某些编译器支持
它在栈上动态分配内存,不需要手动释放
然而,由于栈的大小有限,`alloca`可能导致栈溢出
此外,由于`alloca`分配的内存由编译器自动管理,其生命周期从程序开始到结束,因此使用`alloca`时需要格外小心
在用户空间中,使用这些内存分配函数后,必须确保在不再需要内存时调用相应的内存释放函数来释放它,以避免内存泄漏
对于`malloc`、`calloc`和`realloc`分配的内存,应使用`free`函数进行释放
内核空间内存分配函数 在内核空间中,内存分配主要通过Linux内核提供的内存分配函数实现
这些函数包括`kmalloc`、`vmalloc`、`get_free_pages`、`alloc_pages`等
1.kmalloc函数 `kmalloc`函数用于分配指定大小的连续物理内存块,并返回指向该内存块的指针
其原型为`void kmalloc(size_t size, gfp_tflags)`
`flags`参数用于控制内存分配的行为和特性
`kmalloc`函数与`malloc`函数类似,但前者用于内核态的内存分配,后者用于用户态
`kmalloc`函数在物理内存中分配内存,不会清除里面的原始数据
由于Linux内存管理机制的原因,内存只能按照页面大小进行分配
因此,当需要分配的内存较小时,系统仍会返回一个页面的内存,这可能导致内存浪费
为了优化这种情况,内核先为其分配一系列不同大小的内存池,当需要分配内存时,系统会分配大于等于所需内存的最小一个内存池给它
`kmalloc`分配的内存最小为32字节,最大为128KB
如果需要分配超过128KB的内存,应使用其他内存分配函数,如`vmalloc`
`kmalloc`函数的`flags`参数非常关键,它决定了内存分配的行为
最常用的标志是`GFP_KERNEL`,表示当当前没有足够内存分配时,进程进入睡眠状态,待系统将缓冲区中的内容SWAP到硬盘中后,获得足够内存后再唤醒进程,为其分配内存
然而,`GFP_KERNEL`标志会引起阻塞,因此不能在中断上下文或持有自旋锁的时候使用
在中断处理函数、tasklet和内核定时器等非进程上下文中,应使用`GFP_ATOMIC`标志来申请内存
`GFP_ATOMIC`标志表示若不存在空闲页,则不等待,直接返回
2.vmalloc函数 `vmalloc`函数用于分配虚拟内存,而不是连续的物理内存
其原型为`void vmalloc(unsigned long size)`
分配的内存可能分布在多个物理页面上,但对进程来说是连续的
由于需要建立新的页表,`vmalloc`的开销要远远大于`kmalloc`
`vmalloc`函数一般用在为只存在于软件中(没有对应的硬件意义)的较大的顺序缓冲区分配内存
当内存没有足够大的连续物理空间可以分配时,可以使用`vmalloc`函数来分配虚拟地址连续但物理地址不连续的内存
3.页分配函数 在Linux中,内存分配是以页为单位的
32位系统中一页为4KB,64位系统中一页为8KB(具体根据平台而定)
页分配函数根据返回值类型的不同,分为返回物理页地址和返回虚拟地址两类
根据返回页面数目分类,分为仅返回单页面的函数和返回多页面的函数
alloc_page和alloc_pages函数 `alloc_page`和`alloc_pages`函数用于分配一个或多个连续的物理页
它们返回分配的第一个页的描述符而非首地址
这些函数定义在头文件`/include/linux/gfp.h`中
__get_free_pages系列函数 `__get_free_pages`系列函数是`kmalloc`函数实现的基础,返回一个或多个页面的虚拟地址
它们用于分配特定数量的连续物理页(以2的幂为单位)和单个物理页
其他内核空间内存分配函数 除了上述常见的内存分配函数外,Linux内核还提供了其他内存分配函数,以满足特定场景下的需求
dma_alloc_coherent函数 `dma_alloc_coherent`函数在设备映射区域分配一块连续的物理内存,以便于DMA传输
分配的内存对于处理器来说是可直接访问的,并且确保不会被内核抢占或迁移
kzalloc函数 `kzalloc`函数类似于`kmalloc`函数,但在分配内存后将其所有字节初始化为0
这使得`kzalloc`非常适合用于需要初始化为零的数据结构
kfree函数 `kfree`函数用于释放通过上述内核内存分配函数分配的内存
其用法与用户空间的`free`函数类似
内存管理注意事项 在使用Linux内存分配函数时,需要注意以下几点: 1.内存泄漏:确保在不再需要内存时正确释放它,以避免内存泄漏
2.并发访问:考虑到并发访问和竞态条件的问题,可能需要对内存访问进行同步
3.性能优化:根据具体需求选择适当的内存分配函数,以优化性能
例如,对于小块内存的频繁分配和释放,可以使用slab分配器
结语 Linux内存分配函数是Linux操作系统中不可或缺的一部分
它们提供了高效、灵活的内存管理机制,满足了不同场景下的内存需求
通过深入理解这些内存分