1. Linux内核内存分配基础
在Linux内核开发中,内存管理是最核心的子系统之一。与用户空间不同,内核空间的内存分配有着更严格的限制和特殊的使用场景。理解内核内存分配机制对于驱动开发、性能调优和系统稳定性都至关重要。
1.1 物理连续内存分配:kmalloc
kmalloc是内核中最常用的内存分配函数,它分配的是物理地址连续的内存块。这种连续性对于需要直接内存访问(DMA)的设备尤为重要,因为许多硬件设备要求操作的物理内存是连续的。
1.1.1 kmalloc函数详解
kmalloc的函数原型如下:
c复制void *kmalloc(size_t size, gfp_t flags);
参数解析:
size:请求分配的字节数。注意内核有最大分配限制,通常为128KB-4MB(取决于架构和内核配置)flags:分配标志,控制分配行为和内存区域
常用分配标志:
GFP_KERNEL:标准内核内存分配,可能阻塞(即可能触发页面回收或I/O操作)GFP_ATOMIC:原子分配,不会休眠,用于中断上下文等不能休眠的场景GFP_DMA:为DMA分配内存,确保内存位于DMA可访问的区域
实际开发中,
GFP_KERNEL是最常用的标志,但在以下场景必须使用GFP_ATOMIC:
- 中断处理程序
- 持有自旋锁的代码段
- 任何不能休眠的上下文
1.1.2 内存释放与使用示例
内存释放使用kfree函数:
c复制void kfree(const void *objp);
一个典型的使用示例如下:
c复制#include <linux/slab.h>
char *buffer;
/* 分配1KB内存 */
buffer = kmalloc(1024, GFP_KERNEL);
if (!buffer) {
/* 处理分配失败 */
return -ENOMEM;
}
/* 使用内存 */
memset(buffer, 0, 1024);
/* 释放内存 */
kfree(buffer);
注意事项:
- 分配失败必须检查返回值,内核没有用户空间的OOM killer机制
- 释放后应将指针置NULL,避免悬垂指针
- 不要尝试释放非kmalloc分配的内存或重复释放
1.2 虚拟连续内存分配:vmalloc
vmalloc分配的内存只在虚拟地址空间连续,物理地址可能不连续。这种分配方式适用于需要大块内存但不要求物理连续性的场景。
1.2.1 vmalloc函数详解
vmalloc的函数原型:
c复制void *vmalloc(unsigned long size);
特点:
- 分配的内存大小理论上可达1GB(实际受系统配置限制)
- 分配速度比kmalloc慢,因为需要建立页表映射
- 不能用于DMA操作,因为物理地址不连续
1.2.2 使用示例
c复制#include <linux/vmalloc.h>
void *large_buffer;
/* 分配10MB内存 */
