Linux内核内存分配函数

本文深入探讨了Linux内核中的内存分配策略,包括kmalloc、get_free_pages、alloc_pages等函数的应用场景及特点,同时介绍了Slab高速缓存、内存池、perCUP等高级内存管理技术,以及vmalloc、per_cpu等特殊用途的内存分配方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

i. 分配函数的选择

kmalloc():如果需要连续的物理页,可以使用此函数,这是内核中内存分配的常用方式,也是大多数情况下应该使用的内存分配方式。传递给函数的最常用的标志是GTP_ATOMIC和GTP_KERNEL。前面的标志表示进行不睡眠的高优先级分配。在中断处理程序和其他不能睡眠的代码段中需要。后面的标志可以睡眠,在没有持自旋锁的进程上下文中使用。此函数返回内核逻辑地址。

get_free_pages():如果模块需要分配大块的内存,使用此面向页的分配技术。返回内核逻辑地址。

alloc_pages():想从高端内存中分配,就使用此函数。但返回一个指向page结构的指针。为了获得真正的指针,应该调用kmap(),把高端内存映射到内核的虚拟地址空间。

vmalloc():不需要物理上连续的页,仅仅需要虚拟地址上连续的页。

Slab高速缓存:多次创建和销毁较大的数据结构。

内存池:内核有些地方的内存分配不允许失败,为了确保这种情况的成功分配,内核开发者建立了内存池的抽象。内存池其实就是某种形式的后备高速缓存。mempool_create建立内存池对象,mempool_alloc创建内存池。

perCUP:减少数据锁定,大大减少缓存失效。唯一的要求是要禁止内核抢占。

ii.  alloc_pages()

该函数分配连续的物理页,并返回一个指针,指针指向第一个页的page结构体。可以用kmap()函数把此页转换成逻辑地址。此函数可以在高端内存或普通内存分配物理页。

iii. get_free_pages()

此函数与alloc_pages()作用相同,但它直接返回所请求的第一个页的逻辑地址。此函数不能从高端内存分配物理页。

iv. void *kmalloc(size_t size, int flags)

可以获得以字节为单位的内核内存。参数flags有三类标志:行为描述符,区描述符以及类型。

行为修饰符:不常用,忽略。

描述符:__GFP_DMA从ZONE_DMA分配。

__GFP_HIGHMEM从ZONE_HIGHMENZONG_NORMAL分配。

类型标志:GFP_KERNEL,常规分配方式,可能阻塞。用于进程上下文中。

                     GFP_ATOMIC,高优先级的,不会睡眠。用着中断处理程序,下半部,

不能睡眠的地方

v.  vmalloc

工作方式类似于kmalloc(), 不过虚拟地址连续,物理地址不连续。获得大块内存时使用。

vi. slab高速缓存

slab高速缓存一般用于数据频繁分配和回收,如inode和task_struct数据结构。

1. slab层设计

   

2. slab分配器接口使用

    下面以进程描述符task_struct为例说明slab分配器接口使用:

   

3. slab着色

    让slab缓存的对象在CPU的cache彼此错开,不会造成CPU cache频频失效

vii. percpu

1. 定义CPU变量

    a) 编译时定义:DEFINE_PER_CPU(type, name);

    b) 动态定义:void *alloc_percpu(type)

                             void *__alloc_percpu(size_t size, size_t,aligh);

        释放CPU变量:void free_percpu(const void *);

2. 获取CPU数据

    a) get_cpu_ptr(ptr); //返回一个void类型指针,指向处理器的ptr拷贝

    b) put_cpu_ptr(ptr);//完成:重新激活内核抢占

3. 实例说明

   

4. 返回数据:per_cpu_ptr(ptr,cpu);

    此函数返回指定处理器的唯一数据。这个函数不会禁止内核抢占,如果需要访问另外处理器的数据,需要给数据上锁。

 


### Linux Kernel 中内存分配函数 `kmalloc` 和 `vmalloc` 的详解及其用法 #### 1. **`kmalloc` 函数** `kmalloc` 是一种高效的内核内存分配函数,适用于分配较小的连续物理内存块。它支持原子环境下的内存分配,并且分配速度较快。 - **特点**: - 分配的是连续的物理内存。 - 支持原子级别的内存分配(通过指定标志位 `GFP_ATOMIC`)。 - 开销低,适合小规模内存分配场景。 - **语法**: ```c void *kmalloc(size_t size, gfp_t flags); ``` 参数解释: - `size`: 请求分配的字节数。 - `flags`: 内存分配标志,控制分配行为(如是否允许睡眠、是否清零等)。 - **示例代码**: ```c #include <linux/slab.h> static char *buffer; int example_function(void) { buffer = kmalloc(1024, GFP_KERNEL); // 分配 1KB 大小的内存 if (!buffer) { pr_err("Memory allocation failed!\n"); return -ENOMEM; } memset(buffer, 0, 1024); // 初始化缓冲区 pr_info("Allocated %zu bytes using kmalloc.\n", 1024); return 0; } void cleanup_example(void) { kfree(buffer); // 释放由 kmalloc 分配的内存 pr_info("Freed memory allocated with kmalloc.\n"); } ``` #### 特殊形式:`kzalloc` `kzalloc` 是 `kmalloc` 的封装版本,默认会对分配的内存进行清零操作,简化了开发者的工作流程[^2]。 - **语法**: ```c void *kzalloc(size_t size, gfp_t flags); ``` - **示例代码**: ```c static char *zeroed_buffer; int example_kzalloc(void) { zeroed_buffer = kzalloc(1024, GFP_KERNEL); // 分配并自动清零 1KB 内存 if (!zeroed_buffer) { pr_err("Memory allocation failed!\n"); return -ENOMEM; } pr_info("Allocated and cleared %zu bytes using kzalloc.\n", 1024); return 0; } void cleanup_kzalloc(void) { kfree(zeroed_buffer); // 释放由 kzalloc 分配的内存 pr_info("Freed memory allocated with kzalloc.\n"); } ``` #### 2. **`vmalloc` 函数** `vmalloc` 提供了一种灵活的方式来分配大块内存,尤其当需要跨越多个页面时非常有用。然而,它的效率相对较低,因为需要额外的时间来设置页表。 - **特点**: - 分配的是虚拟地址上的连续内存,但对应的物理内存可能是不连续的。 - 更适合大规模内存分配需求。 - 不支持原子级分配,通常在进程上下文中使用。 - **语法**: ```c void *vmalloc(unsigned long size); ``` - **示例代码**: ```c #include <linux/vmalloc.h> static char *large_buffer; int example_vmalloc(void) { large_buffer = vmalloc(1 << 20); // 分配 1MB 大小的内存 if (!large_buffer) { pr_err("Virtual memory allocation failed!\n"); return -ENOMEM; } memset(large_buffer, 0, 1 << 20); // 初始化缓冲区 pr_info("Allocated %lu bytes using vmalloc.\n", 1 << 20); return 0; } void cleanup_vmalloc(void) { vfree(large_buffer); // 释放由 vmalloc 分配的内存 pr_info("Freed virtual memory allocated with vmalloc.\n"); } ``` #### 3. **对比总结** | 功能/特性 | `kmalloc` | `vmalloc` | |-------------------|------------------------------------|-------------------------------------| | **适用范围** | 小型连续内存 | 大型非连续内存 | | **分配时间** | 较短 | 较长(需构建页表) | | **物理连续性** | 连续 | 非连续 | | **原子支持** | 支持 (`GFP_ATOMIC`) | 不支持 | 对于驱动程序开发而言,如果需要快速分配少量连续内存,推荐使用 `kmalloc/kzalloc`;而对于较大的内存需求或无法找到足够的连续物理内存的情况,则可以选择 `vmalloc`[^1][^3]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值