完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
`MCU内置的FLASH和SRAM通常都较小,RT-Thread实时操作系统由于本身需要占用一定的存储单元加上用户代码,因此在应用中如何合理的利用、分配好内存资源尤为重要,在本章节中将于大家一起学习RT-Thread的内存管理。 在RT-Thread官网有介绍两种内存管理方式:动态内存堆管理和静态内存池管理,有兴趣深入了解可以登录RT-Thread官网(https://www.rt-thread.org/document/site/programming-manual/memory/memory/)研究。 在本章节中我们主要讲解在MM32 MCU上使用RT-Thread操作系统如何进行内存管理。 01 概 述 RT-Thread 操作系统在内存管理上,根据上层应用及系统资源的不同,有针对性地提供了不同的内存分配管理算法。总体上可分为两类:内存堆管理与内存池管理,而内存堆管理又根据具体内存设备划分为三种情况: 针对小内存块的分配管理(小内存管理算法) 针对大内存块的分配管理(slab管理算法) 针对多内存堆的分配情况(memheap管理算法) 内存堆可以在当前资源满足的情况下,根据用户的需求分配任意大小的内存块。而当用户不需要再使用这些内存块时,又可以释放回堆中供其他应用分配使用。RT-Thread系统为了满足不同的需求,提供了不同的内存管理算法,分别是小内存管理算法、slab管理算法和memheap管理算法。 内存堆管理用于管理一段连续的内存空间,如下图所示,RT-Thread将 “ZI 段结尾处” 到内存尾部的空间用作内存堆。
图1 内存空间示意图 小内存管理算法 小内存管理算法主要针对系统资源比较少,一般用于小于2MB内存空间的系统。 slab内存管理算法 slab内存管理算法则主要是在系统资源比较丰富时,提供了一种近似多内存池管理算法的快速算法。 memheap管理算法 RT-Thread还有一种针对多内存堆的管理算法,即memheap管理算法。memheap方法适用于系统存在多个内存堆的情况,它可以将多个内存 “粘贴” 在一起,形成一个大的内存堆。 注意 因为内存堆管理器要满足多线程情况下的安全分配,会考虑多线程间的互斥问题,所以不要在中断服务例程中分配或释放动态内存块,因为它可能会引起当前上下文被挂起等待。 针对灵动的MCU,较为适用小内存的内存堆应用,以下介绍小内存管理算法; 小内存管理算法 初始时,它是一块大的内存。当需要分配内存块时,将从这个大的内存块上分割出相匹配的内存块,然后把分割出来的空闲内存块还回给堆管理系统中。每个内存块都包含一个管理用的数据头,通过这个头把使用块与空闲块用双向链表的方式链接起来,如图所示:
图2 小内存管理算法链表结构示意图 每个内存块(不管是已分配的内存块还是空闲的内存块)都包含一个数据头,其中包括: magic 变数(或称为幻数),它会被初始化成 0x1ea0(即英文单词 heap),用于标记这个内存块是一个内存管理用的内存数据块;变数不仅仅用于标识这个数据块是一个内存管理用的内存数据块,实质也是一个内存保护字:如果这个区域被改写,那么也就意味着这块内存块被非法改写(正常情况下只有内存管理器才会去碰这块内存)。 used 指示出当前内存块是否已经分配。 next 指向当前内存块的下一个内存块。 prev 指向当前内存块的上一个内存块。 注意 事实上,next与prev这两个字段保存的是目的地址的一个偏移量,偏移的基地址是整个内存堆空间的起始地址。 内存管理的表现主要体现在内存的分配与释放上,小型内存管理算法可以用以下例子体现出来。 如下图所示的内存分配情况,空闲链表指针 lfree 初始指向 32 字节的内存块。当用户线程要再分配一个 64 字节的内存块时,但此 lfree 指针指向的内存块只有 32 字节并不能满足要求,内存管理器会继续寻找下一内存块,当找到再下一块内存块,128 字节时,它满足分配的要求。因为这个内存块比较大,分配器将把此内存块进行拆分,余下的内存块(52 字节)继续留在 lfree 链表中,如下图分配 64 字节后的链表结构所示。
图3 小内存管理算法链表结构示意图
图4 小内存管理算法链表结构示意图 另外,在每次分配内存块前,都会留出 12 字节数据头用于 magic、used 信息及链表节点使用。返回给应用的地址实际上是这块内存块 12 字节以后的地址,前面的 12 字节数据头是用户永远不应该碰的部分(注:12 字节数据头长度会与系统对齐差异而有所不同)。 释放时则是相反的过程,但分配器会查看前后相邻的内存块是否空闲,如果空闲则合并成一个大的空闲内存块。 02 数据结构描述 下面代码是rtthread中对内存块的结构描述: #define MIN_SIZE 12 //内存申请分配空间的最小值 #define HEAP_MAGIC 0x1ea0 //变数 struct heap_mem { /* magic and used flag */ rt_uint16_t magic; rt_uint16_t used; rt_size_t next, prev; }; 内存分配过程: 设定 空闲链表指针Ifree初始指向32字节的内存块,当用户线程需要分配一个64字节的内存块时,Ifree指针指向的内存块不能满足要求,内存管理器就会继续寻找下一个内存块,当找到时(128字节),就会进行内存分配,如果内存块比较大,分配器就会把内存块进行拆分,余下的内存(52字节)继续留在Ifree链表中。 注意 在内次分配内存块前,都会留出12字节用于magic、used信息及节点使用,返回给应用的地址实际上是这块内存块 12 字节以后的地址,前面的 12 字节数据头是用户永远不应该碰的部分(注:12 字节数据头长度会与系统对齐差异而有所不同)。 释放 释放内存时,分配器会查看前后相邻的内存是否是空闲,如果空闲,就回合并成一个大的空闲内存块。 03 函数实现 我们需要调用的内存堆管理相关的系统函数有5个,如下所示: //在使用内存分配之前,该函数必须被调用,完成内存堆的初始化。 void rt_system_heap_init(void *begin_addr, void *end_addr);
//内存分配函数 void *rt_malloc(rt_size_t size);
//在已分配内存块的基础上重新分配内存块的大小(增加或缩小) void *rt_realloc(void *rmem, rt_size_t newsize);
//从内存堆中分配连续内存地址的多个内存块 void *rt_calloc(rt_size_t count, rt_size_t size);
//内存释放函数 void rt_free(void *rmem);
在分配内存块过程中,用户可设置一个钩子函数,置的钩子函数会在内存分配完成后进行回调。回调时,会把分配到的内存块地址和大小做为入口参数传递进去。RT-Thread提供了分配钩子函数、释放内存等函数接口。 在释放内存中,会有一个内存节点合并功能函数,被rt_free调用,系统编程无需关心。 //内存释放时节点合并 static void plug_holes(struct heap_mem *mem); 04 代码实现 下面我们来看一下基于MM32L062小内存分配算法代码实现创建一个动态的线程,这个线程会动态申请内存并释放,每次申请更大的内存,当申请不到的时候就结束; #include #define THREAD_PRIORITY 25 #define THREAD_STACK_SIZE 512 #define THREAD_TIMESLICE 5 /* 线程入口 */ void thread1_entry(void *parameter) { int i; char *ptr = RT_NULL; /* 内存块的指针 */ for (i = 0; ; i++) { /* 每次分配 (1 << i) 大小字节数的内存空间 */ ptr = rt_malloc(1 << i); /* 如果分配成功 */ if (ptr != RT_NULL) { rt_kprintf("get memory :%d byte ", (1 << i)); /* 释放内存块 */ rt_free(ptr); rt_kprintf("free memory :%d byte ", (1 << i)); ptr = RT_NULL; } else { rt_kprintf("try to get %d byte memory failed! ", (1 << i)); return; } } } int dynmem_sample(void) { rt_thread_t tid = RT_NULL; /* 创建线程 1 */ tid = rt_thread_create("thread1", thread1_entry, RT_NULL, THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); if (tid != RT_NULL) rt_thread_startup(tid); return 0; } /* 导出到 msh 命令列表中 */ MSH_CMD_EXPORT(dynmem_sample, dynmem sample); 2020灵动MM32协作大会 2020年9月10日 9:00 深圳星河丽思卡尔顿酒店 “2020灵动MM32协作大会”重磅开启!大会内容: 新品发布 技术分享 市场分析行业专家热点剖析 合作伙伴现场秀、互动小游戏 热销“MM32 INSIDE”应用案例展演等 更多精彩等着您,欢迎扫码报名参会! ` |
|
相关推荐
|
|
只有小组成员才能发言,加入小组>>
2252个成员聚集在这个小组
加入小组灵动微电子MM32全系列MCU产品应用手册,库函数和例程和选型表
11816 浏览 3 评论
【MM32 eMiniBoard试用连载】+基于OLED12864的GUI---U8G2
5972 浏览 1 评论
【MM32 eMiniBoard试用连载】移植RT-Thread至MM32L373PS
11114 浏览 0 评论
【MM32 eMiniBoard测评报告】+ 开箱 + 初探
4593 浏览 1 评论
灵动微课堂(第106讲) | MM32 USB功能学习笔记 —— WinUSB设备
4325 浏览 1 评论
[MM32软件] MM32F002使用内部flash存储数据怎么操作?
1269浏览 1评论
845浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-22 21:16 , Processed in 0.641778 second(s), Total 68, Slave 50 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号