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)
不连续内存分配 ✅ 支持(通过伙伴系统) ✅ 支持(通过伙伴系统
相关推荐
Ruiery7 小时前
Linux 6.6内核内存管理深度解析(十六):mmap — 用户态“申请内存“的真相
linux·运维·服务器
欧米欧7 小时前
Linux系统篇(七),环境变量的底层溯源,核心获取机制与安全应用
linux·运维·服务器
Ruiery8 小时前
Linux 6.6内核内存管理深度解析(十八):KASLR 内核地址空间随机化
linux·运维·服务器·安全
qetfw8 小时前
UOS MariaDB 数据库:安装、最小权限与备份验证
linux·数据库·mariadb·uos
逆风的蚂蚁10 小时前
linux服务器性能调整怎么落地?我把 CPU 调度、I/O 优先级和内核参数这几个旋钮都拧了一遍
linux·运维·服务器
沫璃染墨14 小时前
从零入门计算机网络系列(十一):HTTP协议进阶——从重定向原理到GET/POST与Fiddler抓包
linux·服务器·开发语言·网络·c++·tcp/ip·html
AI_Lab0115 小时前
宝塔用了两年,有没有必要换成轻量方案?
linux·运维·服务器
by2099915 小时前
Linux GDB 调试与 CGDB 使用
linux·运维·服务器·经验分享
星恒随风16 小时前
Linux网络编程:应用层协议究竟是什么?从网络计算器到TCP Socket抽象基类完整实现
linux·网络·笔记·tcp/ip
feng_you_ying_li19 小时前
linux之网络层
linux·运维·网络