与uc/os内存管理相似,ucgui也存在类似存储控制块的结构,不过它不叫内存控制块,而叫内存分配信息节点(或叫内存管理单元)。方便起见,我们暂且也将其称为存储控制块。存储控制块以数组形式存在,同时也构成双向链表,而ucos中的存储控制块则是单向链表。与ucos内存管理刚好相反,在ucos中的内存控制块链表是用于记录未分配的存储控制块的,而ucgui的双向链表则是用于记录已经分配的存储控制块。

句柄:实际就是数组某一元素的索引号。



uC/GUI动态内存分配过程:

1. 最初,假如进行4次内存申请操作:

(1)最初申请的内存,只要没有进行释放操作,那么所申请的内存块一定都是连续的。

(2)数组中第0个元素始终被系统占用,用于维护链表头结点。所以内存分配必须从索引1开始。

2. 释放掉第2块内存后:

释放内存的操作很简单:

(1)从数组的角度:将该控制块中的Size参数清零,即标记为空闲控制块。

(2)从链表的角度:将该节点从双链表中删除;

3. 申请了一块更大的内存:

(1)从数组的角度,查找空闲存储控制块,即Size参数为0的控制块;

(2)从链表的角度,查找相邻节点之间是否有符合条件的空闲内存;

(3)将(1)找到的控制块插入到(2)中合适的位置。

(4)填充存储控制块的相关信息,并返回数组索引号。

4. 又申请了一块较小的内存:

(1)从数组的角度,查找空闲存储控制块,即Size参数为0的控制块

(2)从链表的角度,查找相邻节点之间是否有符合条件的空闲内存;

(3)将(1)找到的控制块插入到(2)中合适的位置。

(4)填充存储控制块的相关信息,并返回数组索引号。

所以,被占用内存块的排列顺序是与控制块链表的顺序一一对应的。即链表中的Off参数是从低到高排列的,而数组中的Off参数是无序的。

关键函数伪代码

分配函数:_Alloc

_Alloc()

{

(1)调用Size2LegalSize将要分配内存大小调整至最小粒度对齐;

(2)从数组的角度,查找空闲存储控制块,在FindFreeHandle中完成;

(3)从链表的角度,查找相邻节点之间是否有符合条件的空闲内存,在FindHole中完成;

(4)将找到的存储控制块插入链表中合适的位置;

(5)填充控制块相关参数,并将分配的内存块清零;

(6)更新GUI_ALLOC的统计参数;

(7)返回控制块索引号。

}

查找空闲存储控制块函数:FindFreeHandle

FindFreeHandle()

{

(1)从控制块数组索引1开始,查找Size为0的元素;

(2)找到了,返回索引号;没找到,返回0。

}

查找空闲内存函数:FindHole

FindHole()

{

(1)从链表头开始,顺序查找相邻链表之间是否有空闲内存,查找方法:

后一结点Off  -  (前一结点Off + Size)

看后一结点与前一节点之间的间隙是否满足此次分配;

(2)如果(1)找到了符合条件的节点,则返回前一节点的句柄;

如果没找到,则从最后剩余空间开始分配,返回最后一个节点的句柄。

}

释放函数:GUI_ALLOC_Free

GUI_ALLOC_Free()

{

(1)从数组的角度,根据指定的内存句柄,将对应的控制块Size参数清零;

(2)从链表的角度,将该节点从链表中删除;

(3)更新GUI_ALLOC中的统计参数。

}

来源: https://blog.csdn.net/hexiaolong2009