文章目录
计算机系统内存管理
在计算系统中,通常存储空间可以分为两种:内部存储空间和外部存储空间。内部存储空间通常访问速度比较快,能够按照变量地址随机地访问,也就是我们通常所说的 RAM(随机存储器),可以把它理解为电脑的内存;而外部存储空间内所保存的内容相对来说比较固定,即使掉电后数据也不会丢失,这就是通常所讲的 ROM(只读存储器),可以把它理解为电脑的硬盘。
内存堆管理
内存堆管理用于管理一段连续的内存空间,在第三章中介绍过 RT-Thread 的内存分布情况,如下图所示,RT-Thread 将 “ZI 段结尾处” 到内存尾部的空间用作内存堆。

小堆内存管理
- 小堆内存管理模块主要针对系统资源比较少,一般用于小于2MB内存空间的系统,是rt-thread操作系统默认堆内存管理算法,当有可用的内存的时候,会从中分割一块来作为分配的内存,而剩下的则返回到动态内存堆中.算法采用了一个静态链表来实现的,其源码文件在根目录下的src目录下,包含mem.c和mem.h两个文件.
- 警告:因为动态内存管理器要满足多线程情况下的安全分配,会考虑多线程间的互斥问题,所以请不要在中断服务例程中分配或释放动态内存块。因为它可能会引起当前上下文被挂起等待。
初始时,它是一块大的内存,其大小为(MEM_SIZE),当需要分配内存块时,将从这个大的内存块上分割出相匹配的内存块,然后把分割出来的空闲内存块还回给堆管理系统中。每个内存块都包含一个管理用的数据头,通过这个头把使用块与空闲块用双向链表的方式链接起来(内存块链表),具体见图
24-2 和图 24-3。


heap_mem 结构体
#define HEAP_MAGIC 0x1ea0
struct heap_mem
{
/* magic and used flag */
rt_uint16_t magic; /* 如果此内存块被分配了,则置0x1ea0,以此标志此块内存是正常分配出来的,而 */
rt_uint16_t used; /*0:未分配;1:已分配 */
rt_size_t next, prev; /* 前一内存块,后一内存块 */
#ifdef RT_USING_MEMTRACE
rt_uint8_t thread[4]; /* thread name */
rt_uint8_t fun_name[12]; /* 申请函数名 */
rt_uint32_t line; /* 申请函数地址 */
#endif
};
- magic – 变数(或称为幻数),它会被初始化成 0x1ea0(即英文单词 heap),用于标记这个内存块是一个内存管理用的内存数据块;
- used - 指示出当前内存块是否已经分配。
magic 变数不仅仅用于标识这个数据块是一个内存管理用的内存数据块,实质也是一个内存保护字:如果这个区域被改写,那么也就意味着这块内存块被非法改写(正常情况下只有内存管理器才会去碰这块内存)
rt_system_heap_init()初始化动态内存堆
在使用堆内存时,必须要在系统初始化的时候进行堆内存的初始化,一般在系统初始化的时候就分配一大块内存作为堆内存,然后调用 rt_system_heap_init()函数进行系统堆内存初始化,之后我们才能去申请内存,在初始化的时候需要用户自己知道初始化的是哪段内存,所以必须知道内存的起始地址与结束地址,这个函数会把参数 begin_addr,end_addr区域的内存空间作为内存堆来使用,
/* Heap initialization */
#if defined(RT_USING_HEAP)
rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);
#endif
* @ingroup SystemInit
*
* 系统内存堆的配置和初始化,该函数将初始化系统内存堆。
*
* @param begin_addr 系统内存堆的起始地址
* @param end_addr 系统内存堆的结束地址。
*/
void rt_system_heap_init(void *begin_addr, void *end_addr)
{
struct heap_mem *mem;
/* 得到对齐后的堆内存起始地址 */
rt_uint32_t begin_align = RT_ALIGN((rt_uint32_t)begin_addr, RT_ALIGN_SIZE);
/* 得到对齐后的堆内存末尾地址 */
rt_uint32_t end_align = RT_ALIGN_DOWN((rt_uint32_t)end_addr, RT_ALIGN_SIZE);
/* 确保此函数不是运行在中断例程内 */
RT_DEBUG_NOT_IN_INTERRUPT;
/* 确保可用动态堆内存大小至少大于可等于2个内存块控制结构大小 */
if ((end_align > (2 * SIZEOF_STRUCT_MEM)) &&
((end_align - 2 * SIZEOF_STRUCT_MEM) >= begin_align))
{
/* 计算出可用的真实可用作动态分配的内存大小 */
mem_size_aligned = end_align - begin_align - 2 * SIZEOF_STRUCT_MEM;
}
else
{
rt_kprintf("mem init, error begin address 0x%x, and end address 0x%x\n",
(rt_uint32_t)begin_addr, (rt_uint32_t)end_addr);
return;
}
/* heap_ptr为静态全局变量,指用堆内存起始地址 */
heap_ptr = (rt_uint8_t *)begin_align;
RT_DEBUG_LOG(RT_DEBUG_MEM, ("mem init, heap begin address 0x%x, size %d\n",
(rt_uint32_t)heap_ptr, mem_size_aligned));
/* initialize the start of the heap */
/* 将动态堆内存首地址初始化为一个内存块,可用大小为全部可用大小 */
mem = (struct heap_mem *)heap_ptr;
mem->magic = HEAP_MAGIC; /* 初始化为0x1ea0 */
mem->next = mem_size_aligned + SIZEOF_STRUCT_MEM;/* 下一个指向动态堆内存最靠末尾的内存控制结构 */
mem->prev = 0;/*无前一个内存块 */
mem->used = 0;/*初始化为未使用 */
#ifdef RT_USING_MEMTRACE
rt_mem_setname(mem, "INIT");
#endif
/* initialize the end of the heap */
heap_end = (struct heap_mem *)&heap_ptr[mem->next]; /* 指向末尾内存块 */
heap_end->magic = HEAP_MAGIC; /* */
heap_end->used = 1

本文深入探讨RT-Thread操作系统的内存管理机制,包括小堆内存管理模块如何针对资源有限的系统进行高效管理,以及rt_system_heap_init(), rt_malloc(), rt_calloc(), rt_free()等关键函数的工作原理。
最低0.47元/天 解锁文章
1410

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



