《Linux Device Driver》——分配内存

本文详细介绍了Linux内核中内存分配的各种方法,包括kmalloc、分配标志、内存区段、后备高速缓冲区、get_free_page和相关函数、vmalloc以及per-CPU变量。重点讨论了kmalloc的flags参数、size参数,以及不同的内存分配策略和使用场景。同时提到了在特定场景下如引导时分配大缓冲区的方法。
摘要由CSDN通过智能技术生成

kmalloc函数

kmalloc不对所获得的内存空间清零,分配给它的区域保持原有的数据,所分配的区域在物理内存中也是连续的。


flags参数

#include<linux/slab.h>
void *kmalloc(size_t size,int flags);

kmalloc的第一个参数是要分配的块的大小,第二个参数是分配的标志(flags),它能以多种方式控制kmalloc的行为。

最常用的标志是GFP_KERNEL,表示内存分配(最终总是调用get_free_pages来实现实际的分配,这就是GFP_前缀的由来)是代表运行在内核空间的进程执行的。这意味着调用它的函数正代表某给进程执行系统调用。

flags 描述
GFP_KERNEL 内核内存通常的分配方法,可能引起休眠
GFP_ATOMIC 用于在中断处理例程或其它运行于进程上下文之外的代码中分配内存,不会休眠
GFP_USER 用于为用户空间分配内存,可能会引起休眠
GFP_HIGHUSER 类似于GFP_USER,不过如果有高端内存的话就从那里分配
GFP_NOIO 在GFP_KERNEL的基础上,禁止任何I/O的初始化
GFG_NOFS 在GFP_KERNEL的基础上,不允许执行任何文件系统的调用

另外有一些分配标志与上述“或”起来使用

flags 描述
__GFP_DMA 请求分配发生在DMA的内存区段。与使用平台有关
__GFP_HIGHMEM 要分配内存位于高端内存。与使用平台有关
__GFP_COLD 通常,内存分配器会在试图返回“缓存热(cache warm)”页面,即在处理器缓存中找到的页面。相反,这个标志请求尚未使用的“冷”页面。对用于DMA读取的页面分配,可使用这个标志
__GFP_NOWARN 该标准很少使用。它可以避免内核在无法满足分配请求时产生警告(使用printk)
__GFP_HIGH 标记一个高优先级请求,允许未紧急状况而小号由内核保留的最后一些页面
__GFP_REPEAT 告诉分配器在满足分配请求而遇到困难时应采取何种行为:表示“努力再尝试一次”,它会尝试重新分配,但仍可能失败
__GFP_NOFAIL 告诉分配器在满足分配请求而遇到困难时应采取何种行为:始终不返回失败,它会努力满足分配请求(不鼓励使用)
__GFP_NORETRY 告诉分配器在满足分配请求而遇到困难时应采取何种行为:如果所请求的内存不可获得,就立即返回

内存区段

Linux通常把内存分成三个区段:

区段 描述
可用于DMA内存 存在于特别的地址范围
常规内存
高端内存 32位平台为访问(相对)大量内存而存在的一种机制

如果指定了__GFP_DMA标志,则只有DMA区段会被搜索:如果低地址段上没有可用内存,分配就会失败。
如果没有指定特定的标志,即常规区域和DMA区域都会被搜索。
如果设置了__GFP_HIGHMEM标志,则所有三个区段都会被搜索以获取一个空闲页。

**注意:**kmalloc不能分配高端内存


size参数

linux处理内存分配:创建一系列的内存对象池,每个池中的内存块大小是固定一致的。处理分配请求时,就直接在包含有足够大的内存块的池中传递一个整块给请求者。

内核只能分配一些预定义的,固定大小的字节数组。若申请任意数量的内存,则得到的可能会多一些,最多可以得到申请数量的两倍。

size
下限
上限

后备高速缓冲区

驱动程序常常需要反复分配许多相同大小内存块的情况,增加了一些特殊的内存池,称为后备高速缓存(lookaside cache)。 设备驱动程序通常不会涉及后备高速缓存,但是也有例外:在 Linux 2.6 中 USB 和 SCSI 驱动。

Linux 内核的高速缓存管理器有时称为“slab 分配器”,相关函数和类型在 <linux/slab.h> 中声明。slab 分配器实现的高速缓存具有 kmem_cache_t 类型。可以通过kmem_cache_create创建:

kmem_cache_t *kmem_cache_create(const char *name, size_t size,size_t offset,
                  unsigned long flags,
       void (*constructor)(void *, kmem_cache_t *,unsigned long flags),
       void (*destructor)(void *, kmem_cache_t *, unsigned long flags));
/*创建一个可以容纳任意数目内存区域的、大小都相同的高速缓存对象,这些区域的大小都相同,由size参数决定。*/

参数*name: 一个指向 name 的指针,name和这个后备高速缓存相关联,功能是管理信息以便追踪问题;通常设置为被缓存的结构类型的名字,不能包含空格。
参数size:每个内存区域的大小。
参数offset:页内第一个对象的偏移量;用来确保被分配对象的特殊对齐,0 表示缺省值。
参数flags:控制分配方式的位掩码:

flags 描述
SLAB_NO_REAP 保护缓存在系统查找内存时不被削减,不推荐。
SLAB_HWCACHE_ALIGN 所有数据对象跟高速缓存行对齐,平台依赖,可能浪费内存。
SLAB_CACHE_DMA 每个数据对象在 DMA 内存区段分配.。

constructor和destructor参数时可选的函数(但是不能只有destructor而没有constructor);前者用于初始化新分配的对象,后者用于“清除”对象——在内存空间被整个释放给系统之前。

一旦某个对象的高速缓存被创建,就可以调用kmem_cache_alloc从中分配内存对象:

viod *kmem_cache_alloc(kmem_cache_t *cache,int flags
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值