在单片机芯片上,若是不考虑出厂固化的ROM空间的话,一般开发者能接触到的存储空间主要分两种:掉电可保存数据的片内FLASH和掉电不可保存数据的片内RAM。
片内RAM(一般理解为内存)的访问速度比较快,能够按照变量地址随机访问,但断电后数据丢失。片内FLASH(一般理解为硬盘)所保存的内容比较固定,主要用来保存程序自己的数据内容,保存的内容断电不丢失。
对于单片机的片内RAM内存,主要有堆和栈之分,本章的内存管理,主要是基于堆内存管理进行开展的,在RT-Thread中,有两种堆内存管理方式:动态内存堆管理和静态内存池管理。
关于RT-Thread内存管理相关的内容,官方提供了比较丰富的文档做为参考,具体能够查看如下连接:
https://www.rt-thread.org/doc...
本文尝试从如下几个方面总结一下RT-Thread内存管理的学习过程
内存管理相关介绍html
在运行操做系统的单片机上面,代码和变量会占用一部分固定的内存开销,操做系统在初始化的时候,会去除掉这部分已经占用的内存,把剩下的闲置内存归入到系统堆里面进行统一管理,不论是动态堆内存,仍是静态内存池,都是使用这部分闲置空间的。
因为在实时操做系统里面对时间的要求十分严格,为了保证内存分配的时候不影响系统的实时性,就须要确保分配内存的时间是肯定并可控的;而且在内存分配达到必定次数后,就不可避免地产生内存碎片;与此同时,嵌入式设备的内存资源相对有限,有些系统只有几十KB内存,而有些系统则有几十MB。
因此,为了解决以上内存分配可能出现的问题,须要使用一些内存管理算法来进行这些内存分配管理,RT-Thread提供了两种内存管理方式,分别是:动态内存堆管理和静态内存池管理。
动态内存堆管理git
内存堆管理分配主要用于系统动态分配内存的场合,好比,咱们使用动态方式建立某些内核对象(如消息队列,邮箱,信号量,等等)的时候,所使用到的内存空间就是动态内存堆。动态内存堆的意思是,要用多少,系统就分配多少给你,不用的时候,就要进行释放,还给系统再进行统一管理。
关于动态内存堆的管理,主要有三种算法:小内存分配算法,slab算法,memheap算法。关于这三种管理算法的实现原理介绍,RT-Thread官方已经给出了比较详细的解释,这里再也不重复论述。
github
须要注意的是,这三种内存管理算法,咱们只能经过menuconfig来配置系统内核,选择其中一种内存管理方法,对于用户的应用程序接口而言,这三种算法是透明的,也就是说提供给用户的内存管理接口是相同的,只是算法的实现原理不一样。
关于动态堆内存管理,操做系统提供了如下API接口函数,以下图所示。
静态内存池管理算法
在使用动态内存堆管理系统内存的时候,这种方式很是灵活和方便,想用内存的时候就向系统申请分配,不用的时候就释放还给系统,但这种方式也存在必定的弊端。
主要是向系统申请内存的时候,都要遍历一次空闲内存的链表,查找可用的内存块,而后再分配给用户,并且这种方式不可避免地会产生内存碎片,因此这种内存管理方式的效率不是很高。这是一种“用时间换空间”的内存管理方式。
为了提升内存的分配效率,RT-Thread提供了静态内存池管理的方式。静态内存池就是系统把自身管理的内存预先划分为多个固定大小的内存块,当用户须要申请内存的时候,就从这些固定大小的内存块里面申请。
静态内存池管理的方式,还支持线程挂起操做,当系统没有内存块可用时,线程就会挂起等待,直到能申请到可用的内存块,这种特性能够用作线程间同步。安全
关于静态内存池的工做机制,以下图所示。
多线程
RT-Thread提供了如下API函数接口,用于静态内存池管理。
内存堆和内存池的应用示例函数
内存管理相关的应用示例,主要是为了验证动态内存堆管理和静态内存池管理相关的API函数接口,这里包含两个示例,分别是内存堆管理示例和内存池管理示例。学习
示例源码下载连接:
https://github.com/embediot/r...
https://gitee.com/embediot/rt...url
内存堆管理示例会建立一个动态的线程,这个线程会动态申请内存并释放,每次申请更大的内存,当申请不到的时候就结束。例程中分配内存成功并打印信息;当试图申请 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内存,通常采用动态内存堆里面的小内存管理算法便可。