linux中kmalloc函数详解

kmalloc 是个功能强大且高速(除非被阻塞)的工具,所分配到的内存在物理内存中连续且保持原有的数据(不清零)。原型:
#include linux/slab.h>
void *kmalloc(size_t size, int flags);
size 参数
内核管理系统的物理内存,物理内存只能按页面进行分配。kmalloc 和典型的用户空间 malloc 在实际上有很大的差别,内核使用特别的基于页的分配技术,以最好的方式利用系统 RAM。Linux 处理内存分配的方法:创建一系列内存对象集合,每个集合内的内存块大小是固定。处理分配请求时,就直接在包含有足够大内存块的集合中传递一个整块给请求者。
必须注意的是:内核只能分配一些预定义的、固定大小的字节数组。kmalloc 能够处理的最小内存块是 32 或 64 字节(体系结构依赖),而内存块大小的上限随着体系和内核配置而变化。考虑到移植性,不应分配大于 128 KB的内存。若需多于几个 KB的内存块,最好使用其他方法。
flags 参数
内存分配最终总是调用 __get_free_pages 来进行实际的分配,这就是 GFP_ 前缀的由来。
任何标志都定义在 ,有符号代表常常使用的标志组合。
主要的标志常被称为分配优先级,包括:
GFP_KERNEL
最常用的标志,意思是这个分配代表运行在内核空间的进程进行。内核正常分配内存。当空闲内存较少时,可能进入休眠来等待一个页面。当前进程休眠时,内核会采取适当的动作来获取空闲页。所以使用 GFP_KERNEL 来分配内存的函数必须是可重入,且不能在原子上下文中运行。
GFP_ATOMIC
内核通常会为原子性的分配预留一些空闲页。当当前进程不能被置为睡眠时,应使用 GFP_ATOMIC,这样kmalloc 甚至能够使用最后一个空闲页。假如连这最后一个空闲页也不存在,则分配返回失败。常用来从中断处理和进程上下文之外的其他代码中分配内存,从不睡眠。
GFP_USER
用来为用户空间分配内存页,可能睡眠。
GFP_HIGHUSER
类似 GFP_USER,假如有高端内存,就从高端内存分配。
GFP_NOIO

GFP_NOFS
功能类似 GFP_KERNEL,但是为内核分配内存的工作增加了限制。具备GFP_NOFS 的分配不允许执行任何文档系统调用,而 GFP_NOIO 禁止任何 I/O 初始化。他们主要用在文档系统和虚拟内存代码。那里允许分配休眠,但不应发生递归的文档系统调。
Linux 内核把内存分为 3 个区段: 可用于DMA的内存(位于一个特别的地址范围的内存, 外设能够在这里进行 DMA 存取)、常规内存和高端内存(为了访问(相对)大量的内存而存在的一种机制)。目的是使每中电脑平台都必须知道如何将自己特定的内存范围归类到这三个区段中,而不是任何RAM都相同。
当要分配一个满足kmalloc需要的新页时, 内核会建立一个内存区段的列表以供搜索。若指定了 __GFP_DMA, 只有可用于DMA的内存区段被搜索;若没有指定特别的标志, 常规和 可用于DMA的内存区段都被搜索; 若 配置了 __GFP_HIGHMEM,任何的 3 个区段都被搜索(注意:kmalloc 不能分配高端内存)。
内存区段背后的机制在 mm/page_alloc.c 中实现, 且区段的初始化时平台相关的, 通常在 arch 目录树的 mm/init.c中。
有的标志用双下划线做前缀,他们可和上面标志“或”起来使用,以控制分配方式:
__GFP_DMA
需要分配可用于DMA的内存。
__GFP_HIGHMEM
分配的内存能够位于高端内存.
__GFP_COLD
通常,分配器试图返回“缓存热(cache warm)”页面(可在处理器缓存中找到的页面)。 而这个标志请求一个尚未使用的“冷”页面。对于用作 DMA 读取的页面分配,可使用此标志。因为此时页面在处理器缓存中没多大帮助。
__GFP_NOWARN
当一个分配无法满足,阻止内核发出警告(使用 printk )。
__GFP_HIGH
高优先级请求,允许为紧急状况消耗被内核保留的最后一些内存页。
__GFP_REPEAT

__GFP_NOFAIL

__GFP_NORETRY
告诉分配器当满足一个分配有困难时,如何动作。__GFP_REPEAT 表示努力再尝试一次,仍然可能失败; __GFP_NOFAIL 告诉分配器尽最大努力来满足需要,始终不返回失败,不推荐使用; __GFP_NORETRY 告知分配器假如无法满足请求,立即返回。

你可能感兴趣的:(linux中kmalloc函数详解)