当前位置: 首页 > 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.lryc.cn/news/598433.html

相关文章:

  • MYSQL中NOT IN和NOT EXISTS
  • 【Guava】1.1.我的报告
  • 宝塔通过docker部署JupyterHub指南【常见错误处理】
  • 从java到vue3:第二天
  • Vue3 面试题及详细答案120道(91-105 )
  • 个人笔记GUI
  • 【Python】Python多线程爬虫实战:从基础原理到分布式架构实现
  • Linux 基本命令整理
  • #来昇腾学AI 【十天成长计划】大模型LLM Prompt初级班
  • 详解力扣高频 SQL 50 题-1757.可回收且低脂的产品【入门】
  • 保障工业核心命脉:深度解读工业交换机QoS的“智能流量治理”之道
  • docker设置字体及时间,映射到宿主机上
  • rustfs/rustfs基于 Rust 的高性能分布式存储系统
  • 数字系统自动设计:从C++到门级网表
  • EXCEL——INDEX和MATCH傻傻分不清?
  • 基于QT(C++)实现(图形界面)选课管理系统
  • 网易大模型算法面经总结第一篇
  • 【News】同为科技亮相首届气象经济博览会
  • Qt 元对象系统(Meta-Object System)解析
  • 【C#补全计划:类和对象(六)】
  • 【Linux基础知识系列】第六十三篇 - 文件编辑器基础:vim
  • Windows11 本地安装docker Desktop 部署dify 拉取镜像报错
  • 告别下载中断:深入解析Tomcat JSP中的“远程主机强迫关闭连接”与“软件中止连接”
  • BI 系统数据看板全解析:让数据可视化驱动业务决策
  • k8s之ingress定义https访问方式
  • 使用Claude Code从零到一打造一个现代化的GitHub Star项目管理器
  • QT项目-仿QQ音乐的音乐播放器(第二节)
  • 【初识数据结构】CS61B 中的归并排序和选择排序
  • [网安工具] 自动化威胁检测工具 —— D 盾 · 使用手册
  • kubernetes集群中部署CoreDNS服务