linux cma内存分析

0,cma内存

1,linux cma开关

内核宏开关(如CONFIG_CMA)是编译时配置选项,用于决定是否在内核中启用CMA功能。若未启用该宏,整个CMA子系统将不会被编译进内核,系统完全失去连续内存分配能力

cma=0是内核启动时传递的命令行参数,用于动态禁用CMA功能。此时内核已编译支持CMA,但通过参数强制关闭其运行时行为,例如不预留或释放已预留的CMA内存区域

2,常用CMA宏及其功能

  1. CONFIG_CMA

    • 功能:决定是否在内核中启用CMA功能。
    • 说明:若启用,内核将支持CMA子系统,包括连续内存的分配和释放;若禁用,CMA相关代码将不会被编译进内核,系统将无法使用CMA功能。
  2. CONFIG_CMA_AREAS

    • 功能:定义系统中CMA区域的数量。
    • 说明:通过该宏可以指定内核支持的CMA区域数量,每个区域可以独立配置大小和用途,适用于多设备场景。
  3. CONFIG_CMA_DEBUG

    • 功能:启用CMA的调试功能。
    • 说明:开启后,内核会输出CMA相关的调试信息,便于开发者分析和排查问题。
  4. CONFIG_DMA_CMA

    • 功能:启用CMA与DMA(Direct Memory Access)的集成支持。
    • 说明:该宏用于配置CMA是否支持DMA操作,常用于需要高效内存管理的设备驱动程序1。
  5. CONFIG_CMA_SIZE 定义具体大小(例如 CONFIG_CMA_SIZE_MBYTES=64 表示预留 64MB)

3,GFP_ATOMIC与GFP_KERNEL的功能与区别

(1)GFP_ATOMIC

  • 功能:GFP_ATOMIC是一种内存分配标志,用于在原子上下文中分配内存。它不会引起休眠,因此适用于中断处理程序或持有自旋锁的场景12。
  • 特点
    • 不允许休眠,分配失败时立即返回。
    • 通常用于分配小块内存,不适合分配大块连续内存。
  • 与CMA的关系:GFP_ATOMIC不直接涉及CMA,因为它主要用于非连续内存的分配,且分配过程不会调用CMA的页面迁移机制12。

(2) GFP_KERNEL

  • 功能:GFP_KERNEL是内核中最常用的内存分配标志,用于在进程上下文中分配内存。如果内存不足,它会触发休眠,直到有可用内存为止12。
  • 特点
    • 允许休眠,适用于非原子上下文。
    • 可以分配连续内存和不连续内存,具体取决于分配方式。
  • 与CMA的关系:当使用GFP_KERNEL分配连续内存时,可能会调用CMA机制。如果普通内存区域不足,CMA会通过迁移页面来满足分配需求5

4,GFP_ATOMIC和 GFP_KERNEL的源码实现

(1)GFP_ATOMIC分析

#define GFP_ATOMIC (__GFP_HIGH | __GFP_ATOMIC | __GFP_KSWAPD_RECLAIM)

  • __GFP_HIGH:高优先级分配;
  • __GFP_ATOMIC:不允许休眠;
  • __GFP_KSWAPD_RECLAIM:允许 kswapd 进行后台回收。

(2)使用场景

GFP_ATOMIC 主要用于:

  • 中断处理程序;
  • 持有自旋锁的代码;
  • 不允许阻塞的上下文。

(3) 分配路径

GFP_ATOMIC 调用 kmalloc()__get_free_pages(),最终进入 alloc_pages()

(4)GFP_KERNEL 的源码实现

#define GFP_KERNEL (__GFP_RECLAIM | __GFP_IO | __GFP_FS)

  • __GFP_RECLAIM:允许页面回收;
  • __GFP_IO:允许进行 I/O 操作;
  • __GFP_FS:允许进行文件系统操作。

(5) 使用场景

GFP_KERNEL 适用于:

  • 进程上下文;
  • 允许休眠和阻塞的代码。

(6) 分配路径

GFP_KERNEL 同样调用 alloc_pages(),但在 __alloc_pages() 中:

  • 如果空闲内存不足,会触发 __alloc_pages_slowpath()
  • __alloc_pages_slowpath() 中,会尝试:
    • 页面回收(shrink_zones());
    • 直接回收(__perform_reclaim());
    • 如果配置了 CMA,会尝试从 CMA 区域分配连续内存。

5,代码分析

  • include/linux/gfp.h:GFP 标志定义;
  • mm/page_alloc.c:页面分配核心逻辑;
  • mm/cma.c:CMA 分配实现;
  • mm/slab.c:slab 分配器(kmalloc)
  • 连续内存 :通过 __get_free_pages()kmalloc()dma_alloc_coherent() 等函数分配,物理地址连续,适用于 DMA 设备;
  • 非连续内存 :通过 vmalloc()ioremap() 等函数分配,物理地址不连续,虚拟地址连续,适用于大块内存;

内核申请源码分析

特性 GFP_ATOMIC GFP_KERNEL
是否允许休眠 ❌ 不允许 ✅ 允许
是否支持 CMA ❌ 不支持 ✅ 支持
适用场景 中断、自旋锁等原子上下文 进程上下文,允许阻塞
连续内存分配 ❌ 不支持 ✅ 支持(通过 CMA)
不连续内存分配 ✅ 支持(通过伙伴系统) ✅ 支持(通过伙伴系统
相关推荐
张火火isgudi1 天前
fedora43 安装 nvidia 驱动以及开启视频编解码硬件加速
linux·运维·视频编解码·nvidia
IT19951 天前
Qt笔记-使用SSH2进行远程连接linux服务器并上传文件
linux·服务器·笔记
XXYBMOOO1 天前
内核驱动开发与用户级驱动开发:深度对比与应用场景解析
linux·c++·驱动开发·嵌入式硬件·fpga开发·硬件工程
lengjingzju1 天前
一网打尽Linux IPC(三):System V IPC
linux·服务器·c语言
大聪明-PLUS1 天前
如何编写你的第一个 Linux 内核模块
linux·嵌入式·arm·smarc
知识分享小能手1 天前
Ubuntu入门学习教程,从入门到精通,Ubuntu 22.04文件压缩与解压缩知识点详解(12)
linux·学习·ubuntu
用户6135411460161 天前
Krb5-libs-1.18.2-5.ky10.x86_64.rpm 安装失败怎么办?附详细步骤
linux
zhougl9961 天前
Vuex 模块命名冲突:问题解析与完整解决方案
linux·服务器·apache
一世琉璃白_Y1 天前
Ubuntu(VMware)虚拟机网络异常排查与解决方案
linux·网络·ubuntu
AI+程序员在路上1 天前
网桥及IP转发在嵌入式linux eth0与wlan0连接使用方法
linux·tcp/ip·php