Tiniux 3.0 Memory.c 詳解 -- OSMemMalloc 和 OSMemCalloc
阿新 • • 發佈:2018-11-15
---------------------------------------------
-- 時間: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!)