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)
不连续内存分配 ✅ 支持(通过伙伴系统) ✅ 支持(通过伙伴系统
相关推荐
早起的年轻人4 分钟前
CentOS 8系统盘大文件查找方法
linux·运维·centos
心灵宝贝4 分钟前
Linux CentOS 7 安装 zip-3.0-11.el7.x86_64.rpm 详细步骤(命令行教程)(附安装包)
linux·运维·centos
挺6的还8 分钟前
50.Reactor反应堆模式
linux
Thexhy25 分钟前
在Centos的Linux中安装Windows10系统
linux·运维·经验分享·学习·centos
Lzc77439 分钟前
Linux的Socket编程之UDP
linux·socket编程之udp
zimoyin2 小时前
Linux 程序使用 STDOUT 打印日志导致程序“假死”?一次线上 Bug 的深度排查与解决
linux·运维·bug
杜子不疼.2 小时前
【Linux】操作系统的认识
linux·运维·服务器
Dovis(誓平步青云)2 小时前
《Gdb 调试实战指南:不同风格于VS下的一种调试模式》
linux·运维·服务器
小-黯2 小时前
Ubuntu离线安装软件包
linux·运维·ubuntu
学不动CV了3 小时前
C语言(FreeRTOS)中堆内存管理分析Heap_1、Heap_2、Heap_4、Heap_5详细分析与解析(二)
linux·c语言·arm开发·stm32·单片机·51单片机