当前位置: 首页 > news >正文

Linux内核中动态内存分配函数解析

在C语言中,动态内存分配通常用于在运行时申请内存。在内核编程中,动态内存分配与用户空间有所不同,因为内核需要更谨慎地处理内存,且不能使用用户空间的库(如glibc)。下面我们将详细分析Linux内核中动态申请内存的函数及其区别。

Linux内核中动态内存分配函数

1. kmalloc

kmalloc函数用于在内核空间申请一块连续的内存区域。它的原型如下:

void *kmalloc(size_t size, gfp_t flags);
  • 参数
    • size:要分配的内存大小(以字节为单位)。
    • flags:分配标志,用于指定分配内存的行为和内存类型(例如GFP_KERNELGFP_ATOMIC等)。
  • 返回值:成功时返回指向分配内存的指针,失败时返回NULL
  • 特点
    • 分配的内存是物理上连续的(在虚拟地址空间也是连续的)。
    • 分配的大小有限制(通常最大为4MB,但具体取决于配置和架构)。
    • 适用于需要小块连续内存的情况(如结构体、缓冲区等)。

2. kzalloc

kzallockmalloc的一个变种,它在分配内存的同时将内存初始化为0。原型如下:

void *kzalloc(size_t size, gfp_t flags);
  • 它等价于先用kmalloc分配内存,然后用memset清零。
  • 参数和返回值与kmalloc相同。

3. vmalloc

vmalloc用于分配大块连续虚拟内存(物理内存不一定连续)。原型如下:

void *vmalloc(unsigned long size);
  • 参数
    • size:要分配的内存大小(以字节为单位)。
  • 返回值:成功时返回虚拟地址连续的指针,失败时返回NULL
  • 特点
    • 分配的内存虚拟地址连续,但物理地址可能不连续。
    • 分配的内存可以很大(远大于kmalloc的限制)。
    • 访问速度可能比kmalloc慢,因为需要建立页表映射,且可能引起TLB抖动。
    • 适用于需要大块内存且不需要物理连续性的情况(如模块加载、大型缓冲区等)。

4. kcalloc

kcalloc用于分配数组内存,并将内存初始化为0。原型如下:

void *kcalloc(size_t n, size_t size, gfp_t flags);
  • 参数
    • n:数组元素个数。
    • size:每个元素的大小。
    • flags:同kmalloc
  • 返回值:成功返回指针,失败返回NULL
  • 它分配的内存大小为n * size,并初始化为0。

5. alloc_pages / __get_free_pages

这两个函数用于直接分配页面(以页为单位)。

  • alloc_pages返回struct page *,而__get_free_pages返回虚拟地址。
  • 原型:
    struct page *alloc_pages(gfp_t gfp_mask, unsigned int order);
    unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order);
    
  • 参数
    • gfp_mask:分配标志。
    • order:指定分配页数的对数(即分配页数为2^order)。
  • 它们分配的内存是物理连续的,适用于大块内存需求(但比vmalloc高效,因为物理连续)。

6. kmem_cache_alloc

用于从特定的内存缓存中分配对象。内核中经常需要频繁分配和释放相同大小的内存块(如结构体),使用slab分配器可以提高效率。

  • 首先需要创建一个缓存:
    struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align, unsigned long flags, void (*ctor)(void *));
    
  • 然后从缓存中分配:
    void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags);
    
  • 释放对象到缓存:
    void kmem_cache_free(struct kmem_cache *cachep, void *objp);
    
  • 销毁缓存:
    void kmem_cache_destroy(struct kmem_cache *cachep);
    

区别对比

函数物理连续虚拟连续最大大小适用场景速度
kmalloc/kzalloc较小(如4MB)小内存、需要物理连续
vmalloc很大(如多个GB)大内存、不需要物理连续
kcalloc同kmalloc数组分配并初始化为0
alloc_pages较大(多页)大块物理连续内存
kmem_cache_alloc是(通常)由缓存对象决定频繁分配释放固定大小对象非常快

分配标志(gfp_t flags)常用值

  • GFP_KERNEL:常规分配,可能睡眠(阻塞),适用于进程上下文。
  • GFP_ATOMIC:原子分配,不会睡眠,适用于中断上下文或不能睡眠的地方。
  • GFP_USER:为用户空间分配内存。
  • GFP_HIGHUSER:从高端内存为用户空间分配。
  • GFP_NOIO:禁止I/O操作(在存储管理代码中使用)。
  • GFP_NOFS:禁止文件系统操作(在文件系统代码中使用)。
  • GFP_DMA:分配可用于DMA的内存(物理地址在16MB以下)。
  • GFP_DMA32:分配可用于DMA的内存(物理地址在4GB以下)。

使用注意事项

  1. 上下文要求:在中断上下文、软中断、持有自旋锁等原子上下文中,不能使用可能睡眠的函数(如GFP_KERNEL),而应使用GFP_ATOMIC
  2. 内存泄漏:内核内存不会自动释放,必须显式释放,否则会导致内存泄漏。
  3. 碎片问题:频繁分配释放内存可能导致碎片,使用slab分配器可以减少碎片。
  4. 性能考量vmalloc分配的内存访问速度相对较慢,应避免在性能关键路径中使用。

释放内存的函数

  • kmalloc/kzalloc/kcalloc分配的内存用kfree释放。
  • vmalloc分配的内存用vfree释放。
  • __get_free_pages分配的内存用free_pages释放。
  • alloc_pages分配的内存用__free_pages释放。
  • kmem_cache_alloc分配的内存用kmem_cache_free释放。

示例代码片段

// 使用kmalloc
void *ptr = kmalloc(100, GFP_KERNEL);
if (ptr) {// 使用内存kfree(ptr);
}
// 使用vmalloc
void *vptr = vmalloc(1000000);
if (vptr) {// 使用内存vfree(vptr);
}
// 使用内存缓存
struct kmem_cache *my_cache = kmem_cache_create("my_cache", sizeof(struct my_struct), 0, 0, NULL);
struct my_struct *obj = kmem_cache_alloc(my_cache, GFP_KERNEL);
if (obj) {// 使用对象kmem_cache_free(my_cache, obj);
}
kmem_cache_destroy(my_cache);

以上是Linux内核中动态内存分配的主要函数及其区别。在实际使用中,应根据具体需求选择合适的内存分配函数。

http://www.dtcms.com/a/295511.html

相关文章:

  • 滑动窗口机制及其应用
  • 云渲染的算力困局与架构重构:一场正在发生的生产力革命
  • Apache POI 实战应用:企业级文档处理解决方案
  • 5.7 input子系统
  • uboot FPGA调试环境搭建
  • C++ <多态>详解:从概念到底层实现
  • 不同头会关注输入序列中不同的部分和不同维度所蕴含的信息,这里的头和嵌入维度不是对应的,仅仅是概念上的吗?
  • 在Ubuntu上使用QEMU学习RISC-V程序(1)起步第一个程序
  • 负载均衡-LoadBalance
  • YOLOv4深度解析:革命性的实时目标检测技术
  • 基于Zig语言,opencv相关的c++程序静态交叉编译
  • USRP X440
  • Vulnhub Web-Machine-N7靶机攻略(附VB安装教程)
  • Docker快速安装Clickhouse
  • Vue 项目中的组件引用如何实现,依赖组件间的数据功能交互及示例演示
  • OpenLayers 综合案例-基础图层控制
  • 解密 Base64 编码:从原理到应用的全面解析
  • 前端实现 excel 数据导出,封装方法支持一次导出多个Sheet
  • Effective Python 第16条:用get处理字典缺失键,避免in与KeyError的陷阱
  • 时间日期选择器组件进行日期和时间的禁用处理逻辑
  • 让UV管理一切!!!
  • wiz2025 挑战赛从 SpringActuator 泄露到 s3 敏感文件获取全解析
  • 再生基因总结
  • Vue工程化 ElementPlus
  • Android Camera createCaptureSession
  • 精密圆柱销类分拣系统“cad【9张】三维图+设计书明说
  • 货车手机远程启动的扩展功能有哪些
  • 二次元姓名生成器(饮料名+动漫角色名)
  • 研发过程都有哪些
  • 遨游三防平板|国产芯片鸿蒙系统单北斗三防平板,安全高效