目录
本章讲解RT_Thread Nano实时操作系统的动态内存(内存堆)部分,RT-Thread提供三种动态内存管理算法:小堆内存管理算法、堆内存管理方法、SLAB内存管理算法。小堆内存管理模块主要针对系统资源比较少,一般用于小于2M内存空间的系统;堆内存可以应用于多块不连续的内存堆,SLAB内存管理模块则主要是在系统资源比较丰富时,提供了一种近似多内存池管理算法的快速算法。三种内存管理模块在系统运行时只能选择其中之一或者完全不使用动态堆内存管理器。
三种管理模块提供的API接口完全相同,小堆内存管理算法接口在mem.c,堆内存管理方法在memheap.c文件中定义,SLAB内存管理模块在slab.c文件中定义。
| 内存管理方法 | 适用场景 | 宏定义设置 | 接口定义位置 |
| 小堆内存 | 小于2M内存空间 | RT_USING_HEAP RT_USING_SMALL_MEM |
mem.c |
| 堆内存 | 多块不连续的内存堆 | RT_USING_MEMHEAP_AS_HEAP RT_USING_MEMTRACE |
memheap.c |
| SLAB | 系统资源比较丰富 | RT_USING_HEAP RT_USING_SLAB |
slab.c |
本章主要讲解静态小堆内存管理算法,其特点是内存利用率高,适用于小存储空间。
本章基于RT_Thread Nano V3.1.5版本分析
1、内存堆控制
1.1 内存堆控制器
内存堆控制器由一些全局变量定义,如下所示:
static rt_uint8_t *heap_ptr; // 内存堆首地址
static struct heap_mem *heap_end; // 内存堆尾部节点
static struct heap_mem *lfree; // 指向最低地址空闲块节点,用于管理空闲内存块
static struct rt_semaphore heap_sem; // 内存信号,用于临界资源权限保护
static rt_size_t mem_size_aligned; // 对齐后小堆内存总大小
static rt_size_t used_mem; // 记录已使用字节数
static rt_size_t max_mem; // 记录已使用字节数的最大值
1.2 内存块节点
内存堆链表节点如下所示,宏定义ARCH_CPU_64BIT表示系统内核为64位。
struct heap_mem
{
rt_uint16_t magic; /*内存块标志字,默认0x1ea0*/
rt_uint16_t used; /*=0表示内存块空闲,=1表示内存块被申请*/
#ifdef ARCH_CPU_64BIT
rt_uint32_t resv;
#endif
rt_size_t next, prev; /*next表示上个内存块节点的相对位置,prev表示下个内存块节点的相对位置*/
/*内存监视使能*/
#ifdef RT_USING_MEMTRACE
#ifdef ARCH_CPU_64BIT
rt_uint8_t thread[8]; /* 记录线程名称*/
#else
rt_uint8_t thread[4]; /* 记录线程名称*/
#endif
#endif
};
1.3 内存堆管理
小堆内存中通过一个双向链表管理内存块,每个内存块首定义一个节点,节点按照地址从小到大顺序双向连接。
内存节点参数next, prev非指针变量,而是表示节点地址相对于堆首地址heap_ptr的偏移,通过偏移定位和连接上下内存块节点位置,例如一内存节点指针struct heap_mem *mem,其下个相邻节点位置为heap_ptr[mem->next],上个相邻节点位置为heap_ptr[mem->prev],同时,可计算出其内存块大小为
size=(&heap_ptr(mem->next)-(char*)mem-sizeof(struct heap_mem));
空闲内存块指针*lfree指向地址最低的空闲内存块,内存申请时,从lfree指向位置开始向高地址遍历所有内存块,直至找到合适的空闲内存块。当内存块释放后,需要重新判断和定位lfree位置。
系统内核为64位时,最小内存堆默认24字节,否则默认12字节。最小长度可调。
#ifdef ARCH_CPU_64BIT
#define MIN_SIZE 24
#else
#define MIN_SIZE 12
#endif
2、内存堆初始化
小内存堆通过全局变量管理,将内存区对齐后,首尾各定义一个内存块节点,堆首内存节点为空闲内存块节点,堆尾节点属性是已使用,将2个节点双向连接,并将空闲内存块指针指向堆首节点。
2.1 初始化接口
/**
* 系统堆初始化.
* @param begin_addr 系统堆起始地址
* @param end_addr 系统堆结束地址
*/
void rt_system_heap_init(void *begin_addr, void *end_addr)
2.2 初始化示例
代码示例:
unsigned char heap[1024*1024];
rt_system_heap_init(heap,heap+sizeof(heap));
内存结构图示:初始化完成后lfree指向首节点,heap_end指向尾部节点,收尾节单向链接。已使用字节数used_mem为0,已使用字节数的最大值max_mem为0。

2.3 源码分析
/**
* 系统堆初始化.
* @param begin_addr 系统堆起始地址
* @param end_addr 系统堆结束地址
*/
void rt_system_heap_init(void *begin_addr, void *end_addr)
{

最低0.47元/天 解锁文章
1927

被折叠的 条评论
为什么被折叠?



