---------------------------------------------
-- 时间:2018-11-04
-- 创建人:Ruo_Xiao
-- 邮箱:xclsoftware@163.com
---------------------------------------------
一、前言
1、本博文是我自己的理解,在没有把握的地方我会特别注明。本人菜鸟一枚,真诚地期待大神地指教!
2、Tiniux 3.0下载地址。
3、建议使用Source Inlight看源码,效率更高!
4、为了避免篇幅过长,博文源码中使用的一些数据类型就不多解释了,本文只针对终点区域做详解。
5、根据Memory.h头文件可知,函数一共5个,如下:
uOSBase_t OSMemInit(void);
void *OSMemMalloc(uOSMemSize_t size);
void *OSMemCalloc(uOSMemSize_t count, uOSMemSize_t size);
void *OSMemTrim(void *pMem, uOSMemSize_t size);
void OSMemFree(void *pMem);
二、OSMemInit
1、源码
/*****************************************************************************
Function : OSMemInit
Description : Zero the heap and initialize start, end and lowest-free pointer.
Input : None
Output : None
Return : None
*****************************************************************************/
uOSBase_t OSMemInit(void)
{
tOSMem_t *ptOSMemTemp = OS_NULL;
// align the heap
gpOSMemBegin = (uOS8_t *)OSMEM_ALIGN_ADDR(OSRAM_HEAP_POINTER);
/* Initialize the stack tiniux used. */
memset(gpOSMemBegin, 0U, OSMEM_SIZE_ALIGNED);
// initialize the start of the heap
ptOSMemTemp = (tOSMem_t *)(void *)gpOSMemBegin;
ptOSMemTemp->NextMem = OSMEM_SIZE_ALIGNED;
ptOSMemTemp->PrevMem = 0;
ptOSMemTemp->Used = 0;
// initialize the end of the heap
gpOSMemEnd = (tOSMem_t *)(void *)&gpOSMemBegin[OSMEM_SIZE_ALIGNED];
gpOSMemEnd->Used = 1;
gpOSMemEnd->NextMem = OSMEM_SIZE_ALIGNED;
gpOSMemEnd->PrevMem = OSMEM_SIZE_ALIGNED;
// initialize the lowest-free pointer to the start of the heap
gpOSMemLFree = (tOSMem_t *)(void *)gpOSMemBegin;
return 0U;
}
2、该函数的目的:
(1)将申请的堆初始化为0;
(2)设置指向堆开始位置的tOSMem_t结构体;
(3)设置指向堆结束位置和指向最低位置的已经释放内存的首地址的tOSMem_t结构体。
3、系统内存分布
gpOSMemEnd - gpOSMemBegin = OSMEM_SIZE_ALIGNED
4、tOSMem_t
typedef struct _tOSMem
{
uOSMemSize_t NextMem;
uOSMemSize_t PrevMem;
uOS8_t Used;
}tOSMem_t;
(1)作用:用于记录堆中已分配的和未分配的内存块在系统内存中的位置(首地址)。
(2)NextMem:堆中,下一个tOSMem_t的首地址。
(3)PrevMem:堆中,上一个tOSMem_t的首地址。
(4)Used:指明其后面的内存块是否被分配,0则为分配,非0则已分配。
(5)注意:tOSMem_t中的元素指明的地址是堆中的地址,gpOSMemBegin、gpOSMemEnd 和 gpOSMemLFree首地址都是系统内存中的地址。
5、在系统内存中申请堆
gpOSMemBegin = (uOS8_t *)OSMEM_ALIGN_ADDR(OSRAM_HEAP_POINTER);
(1)OSMEM_ALIGN_ADDR,地址对齐操作。
(2)OSRAM_HEAP_POINTER,堆数组的首地址。
#define OSMEM_SIZE_ALIGNED OSMEM_ALIGN_SIZE(512)
uOS8_t OSRamHeap[OSMEM_SIZE_ALIGNED + (2U*SIZEOF_OSMEM_ALIGNED) + OSMEM_ALIGNMENT];
#define OSRAM_HEAP_POINTER OSRamHeap
A、上述代码的作用是申请512个字节的堆,但是为了在堆中包含两个tOSMem_t(gpOSMemEnd 和 gpOSMemLFree)同时为了数据对齐,则加上了(2U*SIZEOF_OSMEM_ALIGNED) + OSMEM_ALIGNMENT。
B、特别声明:该数组类型为unsigned char,故1个字节即为1个元素,两个tOSMem_t首地址之间的差值就是二者在gpOSMemBegin数组中位置之间的差值。
6、对于刚刚分配好的堆,实际上就2个内存块,一个是ptOSMemTemp信息块和其对应的内存块,另一个是gpOSMemEnd信息块,如下图所示:
1、由于就两个内存块,故:ptOSMemTemp -> NextMem = OSMEM_SIZE_ALIGNED。
由于ptOSMemTemp之前没有节点,故:ptOSMemTemp -> PrevMem = 0,
同时由于该内存块没有分配,故:ptOSMemTemp -> Used = 0。
2、由于gpOSMemEnd的作用是作为堆的尾端,故: gpOSMemEnd -> Used = 1。
同时为了不让其参加运算,孤立它,故:
gpOSMemEnd -> NextMem = OSMEM_SIZE_ALIGNED;
gpOSMemEnd -> PrevMem = OSMEM_SIZE_ALIGNED;
三、拓展
解决了delete []ptr,在delete不知道该ptr数组大小的时候就准确地释放了内存的问题。原因就是在每一个已分配的内存块的前面都添加了相应的信息块,用于存放该存储块首尾在系统内存中的位置,如Tiniux中的tOSMem_t。
(SAW:Game Over!)