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)
不连续内存分配 ✅ 支持(通过伙伴系统) ✅ 支持(通过伙伴系统
相关推荐
phoenix0981几秒前
Linux入门DAY29
linux·运维
入秋25 分钟前
Linux服务器安装部署 Nginx、Redis、PostgreSQL、Docker
linux·前端
Mr. Cao code1 小时前
使用Tomcat Clustering和Redis Session Manager实现Session共享
java·linux·运维·redis·缓存·tomcat
zcz16071278211 小时前
Linux 网络命令大全
linux·运维·网络
the sun341 小时前
Reactor设计模式及其在epoll中的应用
linux·运维·服务器·c++
喜欢你,还有大家1 小时前
Linux笔记7——shell编程基础-1
linux·运维·笔记
运维成长记1 小时前
Top 100 Linux Interview Questions and Answers
linux·运维·服务器
人工智能训练师2 小时前
openEuler系统中如何将docker安装在指定目录
linux·运维·服务器·人工智能·ubuntu
百里晴鸢2 小时前
别再混淆!Linux硬链接与软链接的5大关键区别
linux·操作系统
norsd2 小时前
Linux CentOS 安装 .net core 3.1
linux·centos·.netcore