所谓dynamic_mem就是指可以随时指定一段内存,让程序可以从这段内存中申请内存。dynamic_mem的例程如下:
UINT32 Example_Dyn_Mem(VOID)
{
UINT32 *p_num = NULL;
UINT32 uwRet;
#初始化一段动态内存,形参pDynMem是段内存的起始地址,MEM_DYN_SIZE是这段内存的大小
uwRet = LOS_MemInit(pDynMem, MEM_DYN_SIZE);
if (LOS_OK == uwRet)
{
dprintf("mempool init ok!\n");
}
else
{
dprintf("mempool init failed!\n");
return LOS_NOK;
}
/* mem alloc */
#从前面初始化好的内存中申请内存卡
p_num = (UINT32 *)LOS_MemAlloc(pDynMem, 4);
if (NULL == p_num)
{
dprintf("mem alloc failed!\n");
return LOS_NOK;
}
dprintf("mem alloc ok\n");
/* assignment */
*p_num = 828;
dprintf("*p_num = %d\n", *p_num);
/* mem free */
#将申请的内存块返回给pDynMem
uwRet = LOS_MemFree(pDynMem, p_num);
if (LOS_OK == uwRet)
{
dprintf("mem free ok!\n");
uwRet = LOS_InspectStatusSetByID(LOS_INSPECT_DMEM, LOS_INSPECT_STU_SUCCESS);
if (LOS_OK != uwRet)
{
dprintf("Set Inspect Status Err\n");
}
}
else
{
dprintf("mem free failed!\n");
uwRet = LOS_InspectStatusSetByID(LOS_INSPECT_DMEM, LOS_INSPECT_STU_ERROR);
if (LOS_OK != uwRet)
{
dprintf("Set Inspect Status Err\n");
}
return LOS_NOK;
}
return LOS_OK;
}
用法清楚后,我们先看看如何初始化这段内存
LITE_OS_SEC_TEXT_INIT UINT32 LOS_MemInit(VOID *pPool, UINT32 uwSize)
{
BOOL bRet = TRUE;
UINTPTR uvIntSave;
#可以支持多了不连续的内存,这样提供mempool的指针连在g_pPoolHead中
#if (LOSCFG_MEM_MUL_POOL == YES)
VOID *pNext = g_pPoolHead;
VOID * pCur = g_pPoolHead;
UINT32 uwPoolEnd;
#endif
if (!pPool || uwSize <= sizeof(struct LOS_HEAP_MANAGER))
return LOS_NOK;
if (!IS_ALIGNED(pPool, OS_MEM_POOL_BASE_ALIGN))
return LOS_NOK;
uvIntSave = LOS_IntLock();
#multi pool中查找符合此次分配的mempool
#if (LOSCFG_MEM_MUL_POOL == YES)
while (pNext != NULL)
{
uwPoolEnd = (UINT32)pNext + ((struct LOS_HEAP_MANAGER *)pNext)->uwSize;
if ((pPool <= pNext && ((UINT32)pPool + uwSize) > (UINT32)pNext) ||
((UINT32)pPool < uwPoolEnd && ((UINT32)pPool + uwSize) >= uwPoolEnd))
{
PRINT_ERR("pool [%p, 0x%x) conflict with pool [%p, 0x%x)\n",
pPool, (UINT32)pPool + uwSize,
pNext, (UINT32)pNext + ((struct LOS_HEAP_MANAGER *)pNext)->uwSize);
LOS_IntRestore(uvIntSave);
return LOS_NOK;
}
pCur = pNext;
pNext = ((struct LOS_HEAP_MANAGER *)pNext)->pNextPool;
}
#endif
#核心的初始化
bRet = osHeapInit(pPool, uwSize);
if(!bRet)
{
LOS_IntRestore(uvIntSave);
return LOS_NOK;
}
#还可以使用slab 减少内存碎片
#if (LOSCFG_KERNEL_MEM_SLAB == YES)
if (uwSize >= SLAB_BASIC_NEED_SIZE)//if size of pool is small than size of slab need, don`t init slab
{
bRet = osSlabMemInit(pPool);
if(!bRet)
{
LOS_IntRestore(uvIntSave);
return LOS_NOK;
}
}
#endif
LOS_IntRestore(uvIntSave);
return LOS_OK;
}
继续看
LITE_OS_SEC_TEXT_INIT BOOL osHeapInit(VOID *pPool, UINT32 uwSz)
{
struct LOS_HEAP_NODE* pstNode;
struct LOS_HEAP_MANAGER *pstHeapMan = HEAP_CAST(struct LOS_HEAP_MANAGER *, pPool);
if (!pstHeapMan || (uwSz <= (sizeof(struct LOS_HEAP_NODE) + sizeof(struct LOS_HEAP_MANAGER))))
return FALSE;
#对mempool中的内容清零
memset(pPool, 0, uwSz);
pstHeapMan->uwSize = uwSz;
#将整个mempool 作为一个节点
pstNode = pstHeapMan->pstHead = (struct LOS_HEAP_NODE*)((UINT8*)pPool + sizeof(struct LOS_HEAP_MANAGER));
#尾节点也指向这个节点
pstHeapMan->pstTail = pstNode;
pstNode->uwUsed = 0;
pstNode->pstPrev = NULL;
#这个mempool可以提供分配到size
pstNode->uwSize = uwSz - sizeof(struct LOS_HEAP_NODE) - sizeof(struct LOS_HEAP_MANAGER);
return TRUE;
}
下来我们看看分配函数的实现
LITE_OS_SEC_TEXT VOID* osHeapAlloc(VOID *pPool, UINT32 uwSz)
{
struct LOS_HEAP_NODE *pstNode, *pstT, *pstBest = NULL;
VOID* pRet = NULL;
UINT32 uvIntSave;
#得到提供内存pool的头指针
struct LOS_HEAP_MANAGER *pstHeapMan = HEAP_CAST(struct LOS_HEAP_MANAGER *, pPool);
if (!pstHeapMan)
{
return NULL;
}
uvIntSave = LOS_IntLock();
uwSz = ALIGNE(uwSz);
#得到提供内存pool的尾指针
pstNode = pstHeapMan->pstTail;
while (pstNode)
{
#找到一个size 大于等于要分配uwSz的内存段
if (!pstNode->uwUsed && pstNode->uwSize >= uwSz && (!pstBest || pstBest->uwSize > pstNode->uwSize))
{
#找到要从中分配的内存段
pstBest = pstNode;
#这个段的size刚好等于要分配的size
if (pstBest->uwSize == uwSz)
{
goto SIZE_MATCH;
}
}
pstNode = pstNode->pstPrev;
}
if (!pstBest) /*alloc failed*/
{
PRINT_ERR("there's not enough whole to alloc %x Bytes!\n",uwSz);
goto out;
}
#如果要分配的pool 大于需要的size,则将这个pool分成两部分,一部分分给用户,一部分加到链表中以备下一次使用
if (pstBest->uwSize - uwSz > sizeof(struct LOS_HEAP_NODE))
{
/* hole divide into 2 */
pstNode = (struct LOS_HEAP_NODE*)(pstBest->ucData + uwSz);
pstNode->uwUsed = 0;
pstNode->uwSize = pstBest->uwSize - uwSz- sizeof(struct LOS_HEAP_NODE);
pstNode->pstPrev = pstBest;
#将剩下的size作为一个节点加到链表中
if (pstBest != pstHeapMan->pstTail)
{
if ((pstT = osHeapPrvGetNext(pstHeapMan, pstNode)) != NULL)
pstT->pstPrev = pstNode;
}
else
pstHeapMan->pstTail = pstNode;
pstBest->uwSize = uwSz;
}
SIZE_MATCH:
pstBest->uwAlignFlag = 0;
pstBest->uwUsed = 1;
pRet = pstBest->ucData;
#是要使能task的统计信息
#if (LOSCFG_MEM_TASK_USED_STATISTICS == YES)
OS_MEM_ADD_USED(pstBest->uwSize);
#endif
return pRet;
}
最后看看内存的释放函数
LITE_OS_SEC_TEXT BOOL osHeapFree(VOID *pPool, VOID* pPtr)
{
struct LOS_HEAP_NODE *pstNode, *pstT;
UINT32 uvIntSave;
BOOL bRet = TRUE;
struct LOS_HEAP_MANAGER *pstHeapMan = HEAP_CAST(struct LOS_HEAP_MANAGER *, pPool);
if (!pstHeapMan || !pPtr)
{
return LOS_NOK;
}
/* set to unused status */
pstNode->uwUsed = 0;
#if (LOSCFG_MEM_TASK_USED_STATISTICS == YES)
OS_MEM_REDUCE_USED(pstNode->uwSize);
#endif
#if (LOSCFG_HEAP_MEMORY_PEAK_STATISTICS == YES)
if (g_uwCurHeapUsed >= (pstNode->uwSize + sizeof(struct LOS_HEAP_NODE)))
{
g_uwCurHeapUsed -= (pstNode->uwSize + sizeof(struct LOS_HEAP_NODE));
}
#endif
#按size大小找到这段内存要释放到list中的位置
/* unused region before and after combination */
while (pstNode->pstPrev && !pstNode->pstPrev->uwUsed)
pstNode = pstNode->pstPrev;
#将两块相邻的内存合并,类似于伙伴系统
while (((pstT = osHeapPrvGetNext(pstHeapMan, pstNode)) != NULL) && !pstT->uwUsed)
{
pstNode->uwSize += sizeof(struct LOS_HEAP_NODE) + pstT->uwSize;
if (pstHeapMan->pstTail == pstT)
pstHeapMan->pstTail = pstNode;
}
if ((pstT = osHeapPrvGetNext(pstHeapMan, pstNode)) != NULL)
pstT->pstPrev = pstNode;
OUT:
LOS_IntRestore(uvIntSave);
if (TRUE == bRet)
{
g_uwFreeCount++;
}
return bRet;
}