RT-thread中的头部主要信息如下
struct heap_mem { /* magic and used flag */ uint16_t magic; uint16_t used; uint32_t next, prev; };
在使用动态分配之前需要先初始化一块内存, 接收两个参数, begin_addr为内存起始地址, end_addr为内存终止地址.
void pt_system_heap_init(void *begin_addr, void *end_addr); // 示例用法 // 静态定义一块内存, 大小为HEAP_SIZE字节 static uint8_t heap_mem[HEAP_SIZE]; // 将这块内存的首尾地址作为pt_system_heap_init的参数 pt_system_heap_init(&heap_mem[0], &heap_mem[HEAP_SIZE - 1]);
对一块用于动态分配的内存初始化后如下所示
输入的参数begin_addr和end_addr可能未对齐到4字节, 因此实际使用的内存块可能比定义的要小一些.
lfree指向当前空闲可以分配的内存地址.
malloc函数在这一大块内存中寻找可用的内存, 检查头部used变量, 该块内存是否被占用, 距离下一块内存的空间是否足够等, 若都满足, 则分配使用. 下图是分配一块内存后的示意图.
成功分配一块内存后, 在其后边写入一个信息头, 并将前后内存块的next prev正确设置, lfree也指向了新的空闲内存块.
free函数将释放一块内存, 只是将used标记为0, 表示这块内存不再使用, 但是其内存内容不会清除.
为了避免越分配内存越碎片化, 在free中还检查前后的内存块是不是空闲的, 如果是空闲的则把他们合并起来形成一块大内存, 图中灰色的区域就合并到前一块内存中了.
realloc调整内存大小分为调大和调小.
对于调大的情况, 必须另外分配一块内存, 并将原来内存的数据拷贝到新分配的内存中, 然后释放掉旧内存.
对于调小的情况, 无需另外分配一块内存, 只需在原来的内存上分割即可.