Linux内核内存管理:kmalloc与vmalloc原理及实践

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);

注意事项:

  1. 分配失败必须检查返回值,内核没有用户空间的OOM killer机制
  2. 释放后应将指针置NULL,避免悬垂指针
  3. 不要尝试释放非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内存 */

内容推荐

已经到底了哦
已经到底了哦