共计 2510 个字符,预计需要花费 7 分钟才能阅读完成。
在单片机芯片上,如果不思考出厂固化的 ROM 空间的话,通常开发者能接触到的存储空间次要分两种:掉电可保留数据的片内 FLASH 和掉电不可保留数据的片内 RAM。
片内 RAM(通常了解为内存)的访问速度比拟快,能够依照变量地址随机拜访,但断电后数据失落。片内 FLASH(通常了解为硬盘)所保留的内容比拟固定,次要用来保留程序自身的数据内容,保留的内容断电不失落。
对于单片机的片内 RAM 内存,次要有堆和栈之分,本章的内存治理,次要是基于堆内存治理进行发展的,在 RT-Thread 中,有两种堆内存治理形式:动态内存堆治理和动态内存池治理。
对于 RT-Thread 内存治理相干的内容,官网提供了比拟丰盛的文档作为参考,具体能够查看以下链接:
https://www.rt-thread.org/doc…
本文尝试从以下几个方面总结一下 RT-Thread 内存治理的学习过程
内存治理相干介绍
在运行操作系统的单片机下面,代码和变量会占用一部分固定的内存开销,操作系统在初始化的时候,会去除掉这部分曾经占用的内存,把剩下的闲置内存纳入到零碎堆外面进行对立治理,不论是动静堆内存,还是动态内存池,都是应用这部分闲置空间的。
因为在实时操作系统外面对工夫的要求非常严格,为了保障内存调配的时候不影响零碎的实时性,就须要确保分配内存的工夫是确定并可控的;并且在内存调配达到肯定次数后,就不可避免地产生内存碎片;与此同时,嵌入式设施的内存资源绝对无限,有些零碎只有几十 KB 内存,而有些零碎则有几十 MB。
所以,为了解决以上内存调配可能呈现的问题,须要应用一些内存治理算法来进行这些内存调配治理,RT-Thread 提供了两种内存治理形式,别离是:动态内存堆治理和动态内存池治理。
动态内存堆治理
内存堆治理调配次要用于零碎动静分配内存的场合,比方,咱们应用动静形式创立某些内核对象(如音讯队列,邮箱,信号量,等等)的时候,所应用到的内存空间就是动态内存堆。动态内存堆的意思是,要用多少,零碎就调配多少给你,不必的时候,就要进行开释,还给零碎再进行对立治理。
对于动态内存堆的治理,次要有三种算法:小内存调配算法,slab 算法,memheap 算法。对于这三种治理算法的实现原理介绍,RT-Thread 官网曾经给出了比拟具体的解释,这里不再反复阐述。
须要留神的是,这三种内存治理算法,咱们只能通过 menuconfig 来配置零碎内核,抉择其中一种内存治理办法,对于用户的利用程序接口而言,这三种算法是通明的,也就是说提供给用户的内存治理接口是雷同的,只是算法的实现原理不同。
对于动静堆内存治理,操作系统提供了以下 API 接口函数,如下图所示。
动态内存池治理
在应用动态内存堆管理系统内存的时候,这种形式非常灵活和不便,想用内存的时候就向零碎申请调配,不必的时候就开释还给零碎,但这种形式也存在肯定的弊病。
次要是向零碎申请内存的时候,都要遍历一次闲暇内存的链表,查找可用的内存块,而后再调配给用户,而且这种形式不可避免地会产生内存碎片,所以这种内存治理形式的效率不是很高。这是一种“用工夫换空间”的内存治理形式。
为了进步内存的调配效率,RT-Thread 提供了动态内存池治理的形式。动态内存池就是零碎把本身治理的内存事后划分为多个固定大小的内存块,当用户须要申请内存的时候,就从这些固定大小的内存块外面申请。
动态内存池治理的形式,还反对线程挂起操作,当零碎没有内存块可用时,线程就会挂起期待,直到能申请到可用的内存块,这种个性能够用做线程间同步。
对于动态内存池的工作机制,如下图所示。
RT-Thread 提供了以下 API 函数接口,用于动态内存池治理。
内存堆和内存池的利用示例
内存治理相干的利用示例,次要是为了验证动态内存堆治理和动态内存池治理相干的 API 函数接口,这里蕴含两个示例,别离是内存堆治理示例和内存池治理示例。
示例源码下载链接:
https://github.com/embediot/r…
https://gitee.com/embediot/rt…
内存堆治理示例会创立一个动静的线程,这个线程会动静申请内存并开释,每次申请更大的内存,当申请不到的时候就完结。例程中分配内存胜利并打印信息;当试图申请 65536 byte 即 64KB 内存时,因为开发板的单片机 RAM 总大小只有 64K,而可用 RAM 小于 64K,所以调配失败。
内存池治理示例会创立一个动态的内存池对象,2 个动静线程。一个线程会试图从内存池中取得内存块,另一个线程开释内存块内存块。总共初始化了 4096 /(80+4) = 48 个内存块。
1. 线程 1 申请了 48 个内存块之后,此时内存块曾经被用完,须要其余中央开释能力再次申请;但此时,线程 1 以始终期待的形式又申请了 1 个,因为无奈调配,所以线程 1 挂起;
2. 线程 2 开始执行开释内存的操作;当线程 2 开释一个内存块的时候,就有一个内存块闲暇进去,唤醒线程 1 申请内存,申请胜利后再申请,线程 1 又挂起,再循环一次②;
3. 线程 2 持续开释残余的内存块,开释结束。
在 memory_test.h 头文件外面,通过关上相应的宏定义开关,从新编译工程源码,下载到开发板即可验证试验景象,如下图所示。
内存治理相干注意事项
在应用 RT-Thread 内存治理相干接口的时候,为了确保零碎稳定性,有以下注意事项:
1. 因为零碎为了保障内存在多线程的状态下能平安调配,引入了互斥操作,因而不能在中断服务程序外面调配或开释内存块,否则会引起以后线程被挂起。
2. 在应用内存堆治理的时候,产生的内存碎片会在零碎闲暇线程运行的时候进行回收。
3. 用户应用程序在申请内存调配的时候,倡议判断是否申请胜利,并对申请胜利的内存空间进行初始化后再应用。
4. 动态内存堆治理是一种“用工夫换空间”的内存治理形式,这种形式能够节俭肯定的内存空间,但会损失一点效率。
5. 动态内存池治理是一种“用空间换工夫”的内存治理形式,这种形式相对来说比拟高效,但会造成肯定的空间节约。
6. 对于以 KB 为单位的单片机片内 RAM 内存,个别采纳动态内存堆外面的小内存治理算法即可。
原文链接:https://club.rt-thread.org/as…