1.内存管理模块的算法原理及实现
bcos的内存管理模块预先会以数组的形式开辟一块内存空间,然后以链表的方式去管理内存的申请和释放。当然在管理的过程中链表的头和保存被占用空间的大小等数据会额外的占用一定的空间。在bcos中内存管理链表节点定义如下:
typedef struct
{
slist_t list;
size_t size;
}bcos_mem_t;
每次我们申请一块空间时会额外的占用8个字节用来管理这块被分配的内存空间,如果你每次只申请一个字节这似乎看起来不是很合算,所以尽量不要那样做。 如下图,是初始化和连续申请两次后的内存状态,图中用不同的颜色标注了操作过程:
从图中可以看出,初始化后只有一个链表节点管理了一块很大的内存空间,该节点在free_mem_list中,如果仅有申请的动作,空闲内存块永远是完整的一块,新申请到的内存从空闲内存的尾部分配出来,添加管理链表头后会加入到used_mem_list中。从图中可以看出,如果释放内存的顺序恰好与申请的顺序相反,则会完美的将空闲内存还原成完整的一块。但实际总是事与愿违,但是后续的释放过程会尽力将相挨着的两块内存拼接成完整的一块。大多数情况下是先申请的会先释放,或释放的顺序随机,但有一个将碎片的内存拼接到一起的机制总是好的。
下面给出具体的实现:
#include "bcos_mem.h"
uint8_t heap_mem[BCOS_HEAP_MEM_SIZE];
slist_t bcos_heap_free_head = SLIST_HEAD_INIT(bcos_heap_free_head);
slist_t bcos_heap_used_head = SLIST_HEAD_INIT(bcos_heap_used_head);
bcos_mem_t *heap_mem_head = (bcos_mem_t *)heap_mem;
/*
* 对内存管理列表进行初始化
*/
void bcos_mem_init(void)
{
heap_mem_head->size = BCOS_HEAP_MEM_SIZE - sizeof(bcos_mem_t);
slist_add(&heap_mem_head->list, &bcos_heap_free_head);
}
/* 从内存池中申请内存空间 */
void *bcos_malloc(size_t size)
{
uint8_t *memp = NULL;
bcos_mem_t *pos = NULL, *n = NULL, *prev = NULL;
slist_for_each_entry_safe(pos, n, &bcos_heap_free_head, list)
{
if(pos->size >= size)
{
/* 计算新分配的内存管理指针的值 */
prev = (bcos_mem_t *)((uint8_t *)pos + pos->size - size - sizeof(bcos_mem_t));
prev->size = size;
pos->size = pos->size - size - sizeof(bcos_mem_t);
break;
}
}
if (prev)
{
/* 将分配好的内存插入到已使用的链表中进行管理 */
slist_add(&prev->list, &bcos_heap_used_head);
memp = (uint8_t *) ((uint8_t *)prev + sizeof(bcos_mem_t));
}
return (void *)memp;
}
/* 释放先前分配的内存到内存池 */
void bcos_free(void *memp)
{
bcos_mem_t *pos = NULL, *n = NULL, *del_mem;
slist_t *prev = &bcos_heap_used_head;
/* 对已占用的内存空间进行遍历 */
slist_for_each_entry_safe(pos, n, &bcos_heap_used_head, list)
{
if (pos == (bcos_mem_t *)((uint8_t *)memp - sizeof(bcos_mem_t)))
{
del_mem = pos;
slist_del_init(prev, &del_mem->list);
/* 对各空闲内存空间进行遍历,被释放的内存空间如果可以拼接到现有空闲内存空间上则拼接,如果不可以则按照
地址的顺序作为一个独立链表节点插入到空闲列表中管理 */
slist_for_each_entry_safe(pos, n, &bcos_heap_free_head, list)
{
if(pos <= del_mem && slist_is_last(&pos->list, &bcos_heap_free_head))
{
if(((uint8_t *)pos + pos->size) == (uint8_t *)del_mem)
{
pos->size += (del_mem->size + sizeof(bcos_mem_t));
}
else
{
slist_add(&del_mem->list, &pos->list);
}
break;
}
else if(pos <= del_mem && (del_mem + del_mem->size <= n))
{
if(((uint8_t *)pos + pos->size) == (uint8_t *)del_mem)
{
pos->size += (del_mem->size + sizeof(bcos_mem_t));
if(((uint8_t *)pos + pos->size) == (uint8_t *)n)
{
pos->size += (n->size + sizeof(bcos_mem_t));
slist_del(&pos->list, &n->list);
}
}
else if(((uint8_t *)del_mem + del_mem->size) == (uint8_t *)n)
{
slist_del(&pos->list, &n->list);
del_mem->size += (n->size + sizeof(bcos_mem_t));
slist_add(&pos->list, &del_mem->list);
}
else
{
slist_add(&pos->list, &del_mem->list);
}
}
else
{
continue;
}
break;
}
break;
}
prev = &pos->list;
}
}
|