存储结构示意图:
代码:
/*
* modifier: Honrun
* date: 2021/12/21 20:42
*/
#include "stdio.h"
#include "stdint.h"
#include "DevicesMem.h"
MemType g_typeMemHead = {0};
/* 需要增加 sizeof(MemType) * 2 个长度,以使字节对齐,以及存储管理信息 */
static uint8_t st_MemHeap[DEVICES_MEM_LENGTH + sizeof(MemType) * 2] = {0};
void vMemInit(void)
{
vMemCreate(&g_typeMemHead, st_MemHeap, DEVICES_MEM_LENGTH);
}
static int8_t cMemSet(void *pvMemAddr, int32_t iValue, int32_t iSize)
{
uint32_t *puiData = pvMemAddr;
if((pvMemAddr == NULL) || (iSize < 0))
return -1;
iSize /= 4;
while((iSize--) > 0)
{
*puiData++ = iValue;
}
return 0;
}
static void *pvMemCpy(void *pvMemTargetAddr, void *pvMemSourceAddr, int32_t iSize)
{
uint32_t *puiTargetData = pvMemTargetAddr, *puiSourceData = pvMemSourceAddr;
if((pvMemTargetAddr == NULL) || (pvMemSourceAddr == NULL) || (iSize < 0))
return NULL;
iSize /= 4;
while((iSize--) > 0)
{
*puiTargetData++ = *puiSourceData++;
}
return pvMemTargetAddr;
}
void vMemCreate(MemType *ptypeMemHanle, uint8_t *pucMemHeap, int32_t iLength)
{
MemType *ptypeMemNow = NULL;
/* 地址 N 字节对齐 */
ptypeMemHanle->startAddr = memRoundUp((uint32_t)(pucMemHeap), MEM_ROUNDUP_VALUE);
ptypeMemHanle->stopAddr = ptypeMemHanle->startAddr + iLength;
ptypeMemHanle->state = MEM_UNUSED;
/* 初始化第一个空闲空间 */
ptypeMemNow = (MemType *)ptypeMemHanle->startAddr;
*ptypeMemNow = *ptypeMemHanle;
/* 初始化内存空间末尾的管理信息,标志为已使用是为了在遍历时方便判断退出,以及方便free函数判断 */
ptypeMemNow = (MemType *)ptypeMemHanle->stopAddr;
*ptypeMemNow = *ptypeMemHanle;
ptypeMemNow->state = MEM_USED;
}
void *pvMemMalloc(MemType *ptypeMemHanle, int32_t iSize)
{
void *pvHandle = NULL;
MemType *ptypeMemNow = NULL, *ptypeMemNext = NULL, *ptypeMemMin = NULL;
int32_t iAddrStop = 0, iSizeNow = 0, iSizeMin = 0x7FFFFFFF;
if(iSize < 0)
return NULL;
/* 长度 N 字节对齐 */
iSize = memRoundUp(iSize, MEM_ROUNDUP_VALUE);
/* 遍历mem空间 */
for(ptypeMemNow = (MemType *)ptypeMemHanle->startAddr; (int32_t)ptypeMemNow < ptypeMemHanle->stopAddr; ptypeMemNow = (MemType *)ptypeMemNow->stopAddr)
{
if(ptypeMemNow->state == MEM_UNUSED)
{
iSizeNow = ptypeMemNow->stopAddr - ptypeMemNow->startAddr - sizeof(MemType);
/* 最小空闲匹配 */
if((iSizeNow >= iSize) && (iSizeMin > iSizeNow))
{
iSizeMin = iSizeNow;
ptypeMemMin = ptypeMemNow;
/* 找到刚好相同大小的空闲空间就直接退出遍历 */
if(iSizeMin == iSize)
break;
}
}
}
/* 没匹配到合适的最小空间,表示当前分配不了 */
if(ptypeMemMin == NULL)
return NULL;
/* 标志为已使用 */
ptypeMemMin->state = MEM_USED;
/* 最小匹配空间被划分后还有剩余空间,并能够存储下一个头部信息 */
if((iSizeMin - iSize) >= sizeof(MemType))
{
iAddrStop = ptypeMemMin->stopAddr;
ptypeMemMin->stopAddr = ptypeMemMin->startAddr + sizeof(MemType) + iSize;
ptypeMemNext = (MemType *)ptypeMemMin->stopAddr;
ptypeMemNext->startAddr = ptypeMemMin->stopAddr;
ptypeMemNext->stopAddr = iAddrStop;
ptypeMemNext->state = MEM_UNUSED;
}
/* 扩容,不遗留用不上的小空闲空间 */
else
{
ptypeMemMin->stopAddr = ptypeMemMin->startAddr + sizeof(MemType) + iSizeMin;
}
/* 返回空间管理信息之后的空间地址 */
pvHandle = (void *)(ptypeMemMin->startAddr + sizeof(MemType));
return pvHandle;
}
void *pvMemCalloc(MemType *ptypeMemHanle, int32_t iNumber, int32_t iSize)
{
void *pvHandle = NULL;
int32_t iSizeTemp = iNumber * iSize;
/* 长度 N 字节对齐 */
iSizeTemp = memRoundUp(iSizeTemp, MEM_ROUNDUP_VALUE);
pvHandle = pvMemMalloc(ptypeMemHanle, iSizeTemp);
if(pvHandle != NULL)
{
cMemSet(pvHandle, 0, iSizeTemp);
}
return pvHandle;
}
void *pvMemRealloc(MemType *ptypeMemHanle, void *pvMemAddr, int32_t iSize)
{
void *pvHandle = NULL;
MemType *ptypeMemOld = NULL, *ptypeMemNow = NULL, *ptypeMemNext = NULL;
int32_t iAddrStart = 0, iNewSize = 0, iOldSize = 0;
if(pvMemAddr == NULL)
return NULL;
/* 位移到头部管理信息位置 */
iAddrStart = (int32_t)(pvMemAddr - sizeof(MemType));
if((iAddrStart < ptypeMemHanle->startAddr) || (iAddrStart > ptypeMemHanle->stopAddr))
return NULL;
ptypeMemOld = (MemType *)(iAddrStart);
/* 长度 N 字节对齐 */
iSize = memRoundUp(iSize, MEM_ROUNDUP_VALUE);
/* 计算后续衔接空闲空间的大小 */
for(ptypeMemNow = (MemType *)ptypeMemOld->stopAddr; ptypeMemNow->state == MEM_UNUSED; ptypeMemNow = (MemType *)(ptypeMemNow->stopAddr));
iNewSize = (int32_t)ptypeMemNow - ptypeMemOld->startAddr - sizeof(MemType);
/* 直接拓展衔接的空闲空间 */
if(iNewSize >= iSize)
{
/* 最小匹配空间被划分后还有剩余空间,并能够存储下一个头部信息 */
if((iNewSize - iSize) >= sizeof(MemType))
{
ptypeMemOld->stopAddr = ptypeMemOld->startAddr + sizeof(MemType) + iSize;
ptypeMemNext = (MemType *)ptypeMemOld->stopAddr;
ptypeMemNext->startAddr = ptypeMemOld->stopAddr;
ptypeMemNext->stopAddr = (int32_t)ptypeMemNow;
ptypeMemNext->state = MEM_UNUSED;
}
/* 扩容,不遗留用不上的小空闲空间 */
else
{
ptypeMemOld->stopAddr = ptypeMemOld->startAddr + sizeof(MemType) + iNewSize;
}
return pvMemAddr;
}
/* 重新分配空间 */
else
{
/* 分配不到满足所需大小的空间 */
if((pvHandle = pvMemMalloc(ptypeMemHanle, iSize)) == NULL)
return NULL;
/* 转移拷贝数据 */
iOldSize = ptypeMemOld->stopAddr - ptypeMemOld->startAddr - sizeof(MemType);
pvMemCpy(pvHandle, pvMemAddr, iOldSize);
/* 释放旧空间 */
vMemFree(ptypeMemHanle, pvMemAddr);
return pvHandle;
}
}
void vMemFree(MemType *ptypeMemHanle, void *pvMemAddr)
{
MemType *ptypeMemNow = NULL, *ptypeMemPrev = NULL, *ptypeMemNext = NULL;
int32_t iAddrStart = 0;
if(pvMemAddr == NULL)
return;
/* 位移到头部管理信息位置 */
iAddrStart = (int32_t)(pvMemAddr - sizeof(MemType));
if((iAddrStart < ptypeMemHanle->startAddr) || (iAddrStart > ptypeMemHanle->stopAddr))
return;
ptypeMemNow = (MemType *)(iAddrStart);
ptypeMemNow->state = MEM_UNUSED;
/* 遍历,找到当前待删除空间的前面一个空间 */
for(ptypeMemPrev = (MemType *)(ptypeMemHanle->startAddr); ptypeMemPrev->stopAddr < ptypeMemNow->startAddr; ptypeMemPrev = (MemType *)ptypeMemPrev->stopAddr);
/* 合并前面一个相连的空闲空间 */
if(ptypeMemPrev->state == MEM_UNUSED)
{
ptypeMemPrev->stopAddr = ptypeMemNow->stopAddr;
ptypeMemNow = ptypeMemPrev;
}
/* 合并后面一个相连的空闲空间 */
ptypeMemNext = (MemType *)ptypeMemNow->stopAddr;
if(ptypeMemNext->state == MEM_UNUSED)
{
ptypeMemNow->stopAddr = ptypeMemNext->stopAddr;
}
}
头文件:
#ifndef DEVICESMEM_H_INCLUDED
#define DEVICESMEM_H_INCLUDED
#include "stdint.h"
/* 字节对齐(至少要4字节对齐) */
#define MEM_ROUNDUP_VALUE 8
/* 使x对n字节对齐 */
#define memRoundUp(x, n) (((x) + (n) - 1) & (~((n) - 1)))
/* 此区域内存未使用 */
#define MEM_UNUSED 0
/* 此区域内存已使用 */
#define MEM_USED 1
/* 模拟动态内存大小 */
#define DEVICES_MEM_LENGTH (1024 * 1)
typedef struct{
int32_t startAddr: 30;
int32_t stopAddr: 30;
uint32_t state: 2;
}MemType;
/* 动态内存头部信息 */
extern MemType g_typeMemHead;
void vMemInit(void);
void vMemCreate(MemType *ptypeMemHanle, uint8_t *pucMemHeap, int32_t iLength);
void *pvMemMalloc(MemType *ptypeMemHanle, int32_t iSize);
void *pvMemCalloc(MemType *ptypeMemHanle, int32_t iNumber, int32_t iSize);
void *pvMemRealloc(MemType *ptypeMemHanle, void *pvMemAddr, int32_t iSize);
void vMemFree(MemType *ptypeMemHanle, void *pvMemAddr);
#endif // DEVICESMEM_H_INCLUDED