1. 程式人生 > >Tiniux 3.0 Memory.c 詳解 -- OSMemMalloc 和 OSMemCalloc

Tiniux 3.0 Memory.c 詳解 -- OSMemMalloc 和 OSMemCalloc

---------------------------------------------
-- 時間:2018-11-13
-- 建立人:Ruo_Xiao
-- 郵箱:[email protected]
-- 若大神不吝拋磚,小菜感激不盡!
---------------------------------------------

一、OSMemMalloc 

void* OSMemMalloc(uOSMemSize_t size)
{
//	變數初始化
	//返回最終的已分配的記憶體塊的首地址(不包括tOSMem_t)
    uOS8_t * pResult = OS_NULL;
	//gpOSMemBegin(堆)的迭代器
    uOSMemSize_t ptr = 0U;
	//分配完記憶體塊之後剩餘的空閒塊的在堆中的位置,也是迭代器
    uOSMemSize_t ptr2 = 0U;
    //開始時是較大空閒塊的首地址,由於堆分配是從低地址向高地址分配,分配完成之後,
    //該地址變成了要分配的記憶體塊的首地址,但是包含tOSMem_t,去掉tOSMem_t之後就是pResult。
	tOSMem_t *ptOSMemTemp = OS_NULL;
	//分配完記憶體塊剩餘的空閒塊的首地址
	tOSMem_t *ptOSMemTemp2 = OS_NULL;
//	初始化堆,詳見:https://blog.csdn.net/itworld123/article/details/83998064
    if(gpOSMemEnd==OS_NULL)
    {
        OSMemInit();
        if(gpOSMemEnd==OS_NULL)
        {
            return pResult;
        }
    }
//	不需要分配則返回OS_NULL
    if (size == 0) 
    {
        return pResult;
    }
//  對齊要分配的記憶體塊 
    size = OSMEM_ALIGN_SIZE(size);
//	分配的記憶體塊至少要大於OSMIN_SIZE_ALIGNED
    if(size < OSMIN_SIZE_ALIGNED) 
    {
        // every data block must be at least OSMIN_SIZE_ALIGNED long 
        size = OSMIN_SIZE_ALIGNED;
    }
//	分配的記憶體塊大小超過堆最大值,則返回OS_NULL
    if (size > OSMEM_SIZE_ALIGNED) 
    {
        return pResult;
    }

    // protect the heap from concurrent access 
    OSIntLock();
    
    //	2018-11-10
    //	(uOSMemSize_t)((uOS8_t *)gpOSMemLFree - gpOSMemBegin)	確定閒置tOSMem_t首地址相對Begin的位置
    //	OSMEM_SIZE_ALIGNED - size	搜尋的範圍不能超過待分配記憶體塊的最高地址處
    //	ptr = ((tOSMem_t *)(void *)&gpOSMemBegin[ptr])->NextMem	確定下一個tOSMem_t的位置    
    for (ptr = (uOSMemSize_t)((uOS8_t *)gpOSMemLFree - gpOSMemBegin); ptr < OSMEM_SIZE_ALIGNED - size;
        ptr = ((tOSMem_t *)(void *)&gpOSMemBegin[ptr])->NextMem) 
    {
        ptOSMemTemp = (tOSMem_t *)(void *)&gpOSMemBegin[ptr];

		//1、ptOSMemTemp->Used	該記憶體塊不能被用
		//2、ptOSMemTemp->NextMem - (ptr + SIZEOF_OSMEM_ALIGNED)) >= size	
		//	計算該free指定的空閒塊的大小,其中不包括tOSMem_t,故減掉 SIZEOF_OSMEM_ALIGNED
        if ((!ptOSMemTemp->Used) && (ptOSMemTemp->NextMem - (ptr + SIZEOF_OSMEM_ALIGNED)) >= size) 
        { 
        
			//	分配記憶體的過程就是插入節點(tOSMem_t)的過程。
			//	ptOSMemTemp 				當前節點的首地址(tOSMem_t)
			//	ptOSMemTemp->NextMem		下一個節點的首地址(tOSMem_t)
			//	ptOSMemTemp->NextMem - (ptr + SIZEOF_OSMEM_ALIGNED) 當前節點對應的記憶體塊到下一個記憶體塊對應的tOSMem_t首地址之間的大小
			//	(size + SIZEOF_OSMEM_ALIGNED + OSMIN_SIZE_ALIGNED)	申請記憶體完記憶體之後,在申請的記憶體後面插入新的tOSMem_t,
			//				tOSMem_t和下一個節點之間至少要有一個OSMIN_SIZE_ALIGNED大小的記憶體小塊,否則兩個tOSMem_t就連在
			//				了一起。
			//	如果滿足上述要求,就插入一個節點,否則直接將該記憶體塊設定為要申請的記憶體
            if (ptOSMemTemp->NextMem - (ptr + SIZEOF_OSMEM_ALIGNED) >= (size + SIZEOF_OSMEM_ALIGNED + OSMIN_SIZE_ALIGNED)) 
            {                
                ptr2 = ptr + SIZEOF_OSMEM_ALIGNED + size;
                // 建立 ptOSMemTemp2 資訊塊,該資訊塊對應的記憶體塊大小至少為 OSMIN_SIZE_ALIGNED
                ptOSMemTemp2 = (tOSMem_t *)(void *)&gpOSMemBegin[ptr2];
                ptOSMemTemp2->Used = 0;
                ptOSMemTemp2->NextMem = ptOSMemTemp->NextMem;
                ptOSMemTemp2->PrevMem = ptr;

                ptOSMemTemp->NextMem = ptr2;
                ptOSMemTemp->Used = 1;

                if (ptOSMemTemp2->NextMem != OSMEM_SIZE_ALIGNED) 
                {
                    ((tOSMem_t *)(void *)&gpOSMemBegin[ptOSMemTemp2->NextMem])->PrevMem = ptr2;
                }
            } 
            else 
            {
                ptOSMemTemp->Used = 1;
            }

			//迴圈第一次,此時ptOSMemTemp=gpOSMemLFree。
            if (ptOSMemTemp == gpOSMemLFree) 
            {
				//若gpOSMemLFree完成了記憶體分配,即:Used為1,則更新Free指標。
                while (gpOSMemLFree->Used && gpOSMemLFree != gpOSMemEnd) 
                {
                    gpOSMemLFree = (tOSMem_t *)(void *)&gpOSMemBegin[gpOSMemLFree->NextMem];
                }
            }
			//	返回tOSMem_t對應的的記憶體塊的地址
            pResult = (uOS8_t *)ptOSMemTemp + SIZEOF_OSMEM_ALIGNED;
            break;
        }
    }

    OSIntUnlock();

    return pResult;
}

二、OSMemCalloc 

//Calloc和 Malloc的關係是,前者呼叫後者並且若申請記憶體塊成功則初始化buffer。
//詳見:https://blog.csdn.net/itworld123/article/details/79187109
void* OSMemCalloc(uOSMemSize_t count, uOSMemSize_t size)
{
    void *pMem = OS_NULL;

    // allocate 'count' objects of size 'size' 
    pMem = OSMemMalloc(count * size);
    if (pMem) 
    {
        // zero the memory 
        memset(pMem, 0, count * size);
    }
    return pMem;
}

注:建議將程式碼複製下來,用 VS Code 或者 Notepad++ 審閱效果更加。

 

 

(SAW:Game Over!)