[RK3568 Android11] 教程之kmalloc动态申请内存

本文档详细介绍了RK3568平台Android11系统中,如何使用kmalloc函数动态申请内核内存,包括kmalloc的头文件、函数定义、参数说明、返回值解析,以及配套的释放内存函数kfree的使用。通过代码实例展示了kmalloc的使用场景,并提醒了注意事项,如kmalloc最大内存限制、内存初始化状态和释放内存的重要性。

总目录链接:[RK3568 Android11] 本专栏说明和总目录

目录

前言

一、kmalloc头文件

二、kmalloc函数定义

三、代码演示

四、注意事项


前言

        在内核代码中,如果变量参数需要使用到大量的内存空间,可以使用内存动态申请函数来获取独立的数据存储空间,例如:kmalloc()、kzalloc()和vmalloc()等;此篇讲解kmalloc函数;
        kmalloc函数功能描述:kmalloc()函数动态申请的内存位于物理内存映射区域,分配在物理内存上是连续的,虚拟地址自然也是连续的;kmalloc对申请的内存大小有限制;

一、kmalloc头文件

        头文件:

#include<linux/slab.h>

        头文件路径:

kernel/include/linux/slab.h
### 回答问题 `kmalloc()` 是 Linux 内核中最常用的内存分配函数之一,用于在内核空间中分配**小块、连续的物理和虚拟内存**。它并不是直接调用伙伴系统来分配内存,而是基于 **slab 分配器(或其变种 SLUB/SLAB/SLOB)** 实现的。 > ✅ **`kmalloc()` 通过 slab 分配器申请内存,而 slab 分配器底层使用伙伴系统来获取大块内存页作为缓存池。** --- ### 详细解释 #### 1. `kmalloc()` 的基本用法 ```c #include <linux/slab.h> void *ptr = kmalloc(size, GFP_KERNEL); if (!ptr) return -ENOMEM; // 使用内存 strcpy(ptr, "Hello from kmalloc"); // 释放 kfree(ptr); ``` - `size`: 要分配的字节数(不是页大小,可以是任意小尺寸) - `GFP_KERNEL`: 分配标志,控制行为(是否可睡眠等) --- #### 2. `kmalloc()` 的实现原理:三层结构 Linux 内核中 `kmalloc()` 的实现分为三个层次: ``` +------------------+ | kmalloc() | ← 用户接口,分配任意大小的小内存 +------------------+ ↓ +------------------+ | Slab Allocator | ← SLUB/SLAB 管理固定大小的对象缓存 | (如 kmem_cache) | +------------------+ ↓ +------------------+ | Buddy System | ← 提供 2^order 页的大块内存给 slab 使用 +------------------+ ``` ##### 🔹 第一层:`kmalloc()` 接口 - 内核预定义了一组大小固定的 **kmalloc caches**(例如 `kmalloc-32`, `kmalloc-64`, ..., `kmalloc-8192`) - 当你调用 `kmalloc(100)`,系统会选择最小的大于等于 100 字节的 cache(比如 `kmalloc-128`) ##### 🔹 第二层:Slab 分配器(以 SLUB 为例) - 每个 `kmalloc-N` 对应一个 `struct kmem_cache` - 这些 cache 在启动时由 `create_kmalloc_cache()` 创建 - 分配时从对应的 slab 缓存中取出一个对象 ##### 🔹 第三层:伙伴系统 - 当 slab 缓存中没有空闲对象时,会向伙伴系统申请一页或多页内存作为新的 slab - 例如:`kmalloc-128` 的 slab 可能占用一个页面(4KB),可容纳 32 个对象(4KB / 128B = 32) --- #### 3. 示例代码:`kmalloc()` 如何工作 假设我们调用: ```c char *buf = kmalloc(100, GFP_KERNEL); ``` 内核执行流程如下: ```c kmalloc(100, GFP_KERNEL) └→ __kmalloc(size=100, flags=GFP_KERNEL) └→ kmalloc_slab(size=100) → 找到合适的 cache(如 kmalloc-128) └→ kmem_cache_alloc_trace(cache=kmalloc-128, GFP_KERNEL) └→ slab_alloc() ├→ 如果有空闲对象:直接返回 └→ 否则:slab_reap() → 从 buddy 获取新页 → 构造新 slab ``` 最终返回的内存是: - ✅ 物理连续 - ✅ 虚拟连续 - ✅ 快速分配(因为是从缓存中取) --- #### 4. 查看当前 kmalloc 缓存信息 你可以通过以下命令查看所有 `kmalloc` 相关的 slab 缓存: ```bash cat /proc/slabinfo | grep kmalloc ``` 输出示例(取决于架构和配置): ``` kmalloc-192 0 0 192 21 8 : tunables 0 0 0 : slabdata 0 0 : 0 kmalloc-128 256 256 128 32 8 : tunables 0 0 0 : slabdata 10 10 : 0 kmalloc-96 192 192 96 42 8 : tunables 0 0 0 : slabdata 8 8 : 0 kmalloc-64 512 512 64 64 8 : tunables 0 0 0 : slabdata 8 8 : 0 ``` 字段说明: - 名称:缓存名(`kmalloc-N` 表示每个对象 N 字节) - 第一列数字:已分配的对象数 - 第二列:总对象数 - 第三列:每个对象大小(bytes) - 第四列:每页可容纳对象数 - 第五列:每 slab 的页数(通常为 1) --- #### 5. `kmalloc()` 和 `vmalloc()` / `get_free_pages()` 的对比 | 特性 | `kmalloc()` | `get_free_pages()` | `vmalloc()` | |------|-------------|--------------------|------------| | 物理连续 | ✅ 是 | ✅ 是 | ❌ 否 | | 虚拟连续 | ✅ 是 | ✅ 是 | ✅ 是 | | 分配粒度 | 小对象(≤ 数百 KB) | 页对齐(4KB 倍数) | 任意大小 | | 底层机制 | slab 分配器 | 伙伴系统 | 非连续页表映射 | | 是否阻塞 | 取决于 `GFP_XXX` | 同左 | 可能睡眠 | | 典型用途 | 结构体内存、设备驱动缓冲区 | 大块 DMA 内存 | 大块非连续内存 | --- ### 总结 > 🟩 `kmalloc()` 并不直接使用伙伴系统申请内存 > 🟥 而是通过 **slab 分配器中的预建缓存(如 kmalloc-32, kmalloc-64 等)** 来快速分配 > 🟦 slab 分配器在需要更多内存时,才通过 **伙伴系统分配页框** 来扩充缓存 这种设计的好处: - ⚡️ 快速分配小对象(避免频繁调用伙伴系统) - 🧼 减少内部碎片(按需选择最接近的缓存) - 🔁 支持构造函数、析构函数(面向对象风格) --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

~未来可期~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值