内存管理(三)--Linux CMA内存使用

2024-09-04 11:52
文章标签 linux 使用 内存 管理 cma

本文主要是介绍内存管理(三)--Linux CMA内存使用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 一、预留一段内存常用方法
    • 1.1 设备树定义reserve memory
  • 二、内存节点常见属性
    • 2.1 no-map和reusable使用上的区别
  • 三、预留CMA的reserved memory方法
    • 3.1 共享cma(采用设备树)
    • 3.2 共享cma(采用bootargs)
    • 3.3 私有cma
  • 四、使用reserved memory


我们日常使用kmalloc最多只能动态申请到4M(2^order)内存,当我们需要大块连续内存时,就需要借助CMA申请大内存。
CMA内存分配器在系统中具有多种重要作用,包括分配连续大块内存、提高内存利用率、提供灵活性与可迁移性、优化性能以及简化内存管理等。这些作用共同使得CMA成为嵌入式系统和其他需要连续内存支持的应用场景中的重要技术之一。

前文讲了Linux几种内存预留方法,本文主要讲解Linux里预留CMA内存方法和使用。


一、预留一段内存常用方法

1.1 设备树定义reserve memory

如果需要保留一段内存,在reserved-memory 节点下定义新节点。

reserved-memory {#address-cells = <0x2>;#size-cells = <0x2>;...fb_reserved0: framebuffer{reg = <0x1 0x10000000 0x0 0x8000000>; //addr:0x110000000  128M... //指定这个内存的属性,如:no-map, reusable};....};      

如果要将这个内存私有指定设备里,由指定设备节点使用,通过memory-region字段进行引用(指定给节点fb1使用):

  fb1 {compatible = "xx,xxx";memory-region = <&fb_reserved0>;  //引用这段内存私有到这个设备interrupt-parent = <&gic>;interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;interrupt-names = "xx";...};

二、内存节点常见属性

预留内存可以指定常用的属性,常见有:
1. reusable:表示当前的内存区域除了被dma使用之外,还可以被内存管理(buddy)子系统reuse。
2. no-map:表示是否需要创建页表映射,对于通用的内存,必须要创建映射才可以使用,共享CMA是可以作为通用内存进行分配使用的,因此必须要创建页表映射。
3. linux,cma-default:如果要cma区域为共享区域,需要配置上linux,cma-default属性。 指定了 linux,cma-default 属性,内核在分配 cma 内存时会将这片内存当成默认的 cma 分配池使用,执行内存申请时如果没有指定对应的 cma 就使用默认 cma pool。
4. alignment:对齐参数,保留内存的起始地址需要向该参数对齐
5. alloc-ranges:指定可以用来申请动态保留内存的区间.
6. shared-dma-pool(compatible="shared-dma-pool")
有的时候设备驱动程序需要采用DMA的方式使用预留的内存,对于这种场景,可以dts中的节点属性设置为shared-dma-pool,从而生成为特定设备驱动程序预留的DMA内存池。这样,设备驱动程序仅需要以常规方式使用DMA API。

2.1 no-map和reusable使用上的区别

如上已经介绍了no-map和reusable的特点,显著区别在于这几点:

  1. 是否需要将这块内存进行系统管理,放入buddy中管理。
  2. no-map保留的内存区域已被内核排除,因此iomem信息(/proc/iomem)显示系统RAM小于主板中的内存量。
  3. no-map由于没有创建映射表,因此使用时需要通过ioremap/ioremap_nocache
    /memremap等方式将内存映射出使用。

三、预留CMA的reserved memory方法

cma内存可以理解为是借用了reserve memory节点,可以使用DMA通用映射框架的API对其内存进行申请和使用。
编译内核时需要开启以下配置宏使用cma:

(1)配置宏CONFIG_CMA,启用连续内存分配器。
(2)配置宏CONFIG_CMA_AREAS,指定CMA区域的最大数量,默认值是7。
(3)配置宏CONFIG_DMA_CMA,启用允许设备驱动分配内存的连续内存分配器

cma内存可以将reserve memory分为私有cma和共享cma区域。

3.1 共享cma(采用设备树)

共享cma,将从系统全局自动配置一个连续分配区域 ,所有设备驱动在需要cma内存的时可以从这里面申请,不需要的时候,将作为buddy给系统使用。
标准定义方法如下,定义节点为linux,cma节点定义属性为:shared-dma-pool,reusable,linux,cma-default

reserved-memory {  / / 需要预留内存放在这个reserved-memory节点内定义#address-cells = <0x2>;#size-cells = <0x2>;ranges;cma_reserved: linux,cma {compatible = "shared-dma-pool";reusable;//表示 cma 内存可被 buddy 系统使用size = <0x0 0x80000000>; // 2GBalignment = <0x0 0x2000>; // 8KBlinux,cma-default; //作为cma默认内存池};....
};

3.2 共享cma(采用bootargs)

共享cma也通过内核参数“cma”配置全局CMA区域的大小。
使用内核参数“cma=nn[MG]@[start[MG][-end[MG]]]”设置全局CMA区域的大小和物理地址范围。

3.3 私有cma

reserved memory除了共享cma以外定义方式,其他认为是私有cma。个人认为,为方便区分,cma内存通常指共享池的cma,其他方式的就都称为reserved内存。
如上3.1 案例就是私有cma预留方式,通常配合各种属性对这个内存进行定义。


四、使用reserved memory

当内存compatible为shared-dma-pool。这时候设备驱动程序可以采用DMA的方式去使用预留的内存

  1. 设置设备寻址能力mask: dma_set_coherent_mask/dma_set_mask(一致/非一致性) 。这个会影响cma申请地址大小:2^mask。
  2. 通过of_reserved_mem_device_init来将从设备树memory-region获取内存地址私有化到设备里。
  3. 驱动通过接口dma_alloc_coherentdma_alloc_noncoherent(一致/非一致性)用来分配内存,接口dma_free_coherent和dma_free_noncoherent用来释放内存。

其他类型的内存需要通过如:ioremap/ioremap_nocache/memremap等,映射出内存地址使用。

这篇关于内存管理(三)--Linux CMA内存使用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1135953

相关文章

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

Linux join命令的使用及说明

《Linuxjoin命令的使用及说明》`join`命令用于在Linux中按字段将两个文件进行连接,类似于SQL的JOIN,它需要两个文件按用于匹配的字段排序,并且第一个文件的换行符必须是LF,`jo... 目录一. 基本语法二. 数据准备三. 指定文件的连接key四.-a输出指定文件的所有行五.-o指定输出

Linux jq命令的使用解读

《Linuxjq命令的使用解读》jq是一个强大的命令行工具,用于处理JSON数据,它可以用来查看、过滤、修改、格式化JSON数据,通过使用各种选项和过滤器,可以实现复杂的JSON处理任务... 目录一. 简介二. 选项2.1.2.2-c2.3-r2.4-R三. 字段提取3.1 普通字段3.2 数组字段四.

Linux kill正在执行的后台任务 kill进程组使用详解

《Linuxkill正在执行的后台任务kill进程组使用详解》文章介绍了两个脚本的功能和区别,以及执行这些脚本时遇到的进程管理问题,通过查看进程树、使用`kill`命令和`lsof`命令,分析了子... 目录零. 用到的命令一. 待执行的脚本二. 执行含子进程的脚本,并kill2.1 进程查看2.2 遇到的

详解SpringBoot+Ehcache使用示例

《详解SpringBoot+Ehcache使用示例》本文介绍了SpringBoot中配置Ehcache、自定义get/set方式,并实际使用缓存的过程,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录摘要概念内存与磁盘持久化存储:配置灵活性:编码示例引入依赖:配置ehcache.XML文件:配置

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

k8s按需创建PV和使用PVC详解

《k8s按需创建PV和使用PVC详解》Kubernetes中,PV和PVC用于管理持久存储,StorageClass实现动态PV分配,PVC声明存储需求并绑定PV,通过kubectl验证状态,注意回收... 目录1.按需创建 PV(使用 StorageClass)创建 StorageClass2.创建 PV

Redis 基本数据类型和使用详解

《Redis基本数据类型和使用详解》String是Redis最基本的数据类型,一个键对应一个值,它的功能十分强大,可以存储字符串、整数、浮点数等多种数据格式,本文给大家介绍Redis基本数据类型和... 目录一、Redis 入门介绍二、Redis 的五大基本数据类型2.1 String 类型2.2 Hash

Linux云服务器手动配置DNS的方法步骤

《Linux云服务器手动配置DNS的方法步骤》在Linux云服务器上手动配置DNS(域名系统)是确保服务器能够正常解析域名的重要步骤,以下是详细的配置方法,包括系统文件的修改和常见问题的解决方案,需要... 目录1. 为什么需要手动配置 DNS?2. 手动配置 DNS 的方法方法 1:修改 /etc/res

Redis中Hash从使用过程到原理说明

《Redis中Hash从使用过程到原理说明》RedisHash结构用于存储字段-值对,适合对象数据,支持HSET、HGET等命令,采用ziplist或hashtable编码,通过渐进式rehash优化... 目录一、开篇:Hash就像超市的货架二、Hash的基本使用1. 常用命令示例2. Java操作示例三