0,cma内存
1,linux cma开关
内核宏开关(如CONFIG_CMA
)是编译时配置选项,用于决定是否在内核中启用CMA功能。若未启用该宏,整个CMA子系统将不会被编译进内核,系统完全失去连续内存分配能力
cma=0
是内核启动时传递的命令行参数,用于动态禁用CMA功能。此时内核已编译支持CMA,但通过参数强制关闭其运行时行为,例如不预留或释放已预留的CMA内存区域
2,常用CMA宏及其功能
-
CONFIG_CMA
- 功能:决定是否在内核中启用CMA功能。
- 说明:若启用,内核将支持CMA子系统,包括连续内存的分配和释放;若禁用,CMA相关代码将不会被编译进内核,系统将无法使用CMA功能。
-
CONFIG_CMA_AREAS
- 功能:定义系统中CMA区域的数量。
- 说明:通过该宏可以指定内核支持的CMA区域数量,每个区域可以独立配置大小和用途,适用于多设备场景。
-
CONFIG_CMA_DEBUG
- 功能:启用CMA的调试功能。
- 说明:开启后,内核会输出CMA相关的调试信息,便于开发者分析和排查问题。
-
CONFIG_DMA_CMA
- 功能:启用CMA与DMA(Direct Memory Access)的集成支持。
- 说明:该宏用于配置CMA是否支持DMA操作,常用于需要高效内存管理的设备驱动程序1。
-
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) |
不连续内存分配 | ✅ 支持(通过伙伴系统) | ✅ 支持(通过伙伴系统 |