日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
鴻蒙輕內(nèi)核M核源碼分析系列八靜態(tài)內(nèi)存MemoryBox

想了解更多內(nèi)容,請訪問:

10年積累的網(wǎng)站設(shè)計制作、網(wǎng)站建設(shè)經(jīng)驗,可以快速應(yīng)對客戶對網(wǎng)站的新想法和需求。提供各種問題對應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認識你,你也不認識我。但先做網(wǎng)站后付款的網(wǎng)站建設(shè)流程,更有騰沖免費網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。

和華為官方合作共建的鴻蒙技術(shù)社區(qū)

https://harmonyos.

內(nèi)存管理模塊管理系統(tǒng)的內(nèi)存資源,它是操作系統(tǒng)的核心模塊之一,主要包括內(nèi)存的初始化、分配以及釋放。

在系統(tǒng)運行過程中,內(nèi)存管理模塊通過對內(nèi)存的申請/釋放來管理用戶和OS對內(nèi)存的使用,使內(nèi)存的利用率和使用效率達到最優(yōu),同時最大限度地解決系統(tǒng)的內(nèi)存碎片問題。

鴻蒙輕內(nèi)核的內(nèi)存管理分為靜態(tài)內(nèi)存管理和動態(tài)內(nèi)存管理,提供內(nèi)存初始化、分配、釋放等功能。

動態(tài)內(nèi)存:在動態(tài)內(nèi)存池中分配用戶指定大小的內(nèi)存塊。

  • 優(yōu)點:按需分配。
  • 缺點:內(nèi)存池中可能出現(xiàn)碎片。

靜態(tài)內(nèi)存:在靜態(tài)內(nèi)存池中分配用戶初始化時預(yù)設(shè)(固定)大小的內(nèi)存塊。

  • 優(yōu)點:分配和釋放效率高,靜態(tài)內(nèi)存池中無碎片。
  • 缺點:只能申請到初始化預(yù)設(shè)大小的內(nèi)存塊,不能按需申請。

本文主要分析鴻蒙輕內(nèi)核靜態(tài)內(nèi)存(Memory Box),后續(xù)系列會繼續(xù)分析動態(tài)內(nèi)存。靜態(tài)內(nèi)存實質(zhì)上是一個靜態(tài)數(shù)組,靜態(tài)內(nèi)存池內(nèi)的塊大小在初始化時設(shè)定,初始化后塊大小不可變更。靜態(tài)內(nèi)存池由一個控制塊和若干相同大小的內(nèi)存塊構(gòu)成??刂茐K位于內(nèi)存池頭部,用于內(nèi)存塊管理。內(nèi)存塊的申請和釋放以塊大小為粒度。

本文通過分析靜態(tài)內(nèi)存模塊的源碼,幫助讀者掌握靜態(tài)內(nèi)存的使用。

接下來,我們看下靜態(tài)內(nèi)存的結(jié)構(gòu)體,靜態(tài)內(nèi)存初始化,靜態(tài)內(nèi)存常用操作的源代碼。

1、靜態(tài)內(nèi)存結(jié)構(gòu)體定義和常用宏定義

1.1 靜態(tài)內(nèi)存結(jié)構(gòu)體定義

靜態(tài)內(nèi)存結(jié)構(gòu)體在文件kernel\include\los_membox.h中定義。源代碼如下,⑴處定義的是靜態(tài)內(nèi)存節(jié)點LOS_MEMBOX_NODE結(jié)構(gòu)體,⑵處定義的靜態(tài)內(nèi)存的結(jié)構(gòu)體池信息結(jié)構(gòu)體為LOS_MEMBOX_INFO,,結(jié)構(gòu)體成員的解釋見注釋部分。

 
 
 
 
  1. ⑴  typedef struct tagMEMBOX_NODE { 
  2.         struct tagMEMBOX_NODE *pstNext; /**< 靜態(tài)內(nèi)存池中空閑節(jié)點指針,指向下一個空閑節(jié)點 */ 
  3.     } LOS_MEMBOX_NODE; 
  4.  
  5. ⑵  typedef struct LOS_MEMBOX_INFO { 
  6.         UINT32 uwBlkSize;               /**< 靜態(tài)內(nèi)存池中空閑節(jié)點指針,指向下一個空閑節(jié)點 */ 
  7.         UINT32 uwBlkNum;                /**< 靜態(tài)內(nèi)存池的內(nèi)存塊總數(shù)量 */ 
  8.         UINT32 uwBlkCnt;                /**< 靜態(tài)內(nèi)存池的已分配的內(nèi)存塊總數(shù)量 */ 
  9.     #if (LOSCFG_PLATFORM_EXC == 1) 
  10.         struct LOS_MEMBOX_INFO *nextMemBox; /**< 指向下一個靜態(tài)內(nèi)存池 */ 
  11.     #endif 
  12.         LOS_MEMBOX_NODE stFreeList;     /**< 靜態(tài)內(nèi)存池的空閑內(nèi)存塊單向鏈表 */ 
  13.     } LOS_MEMBOX_INFO; 

 對靜態(tài)內(nèi)存使用如下示意圖進行說明,對一塊靜態(tài)內(nèi)存區(qū)域,頭部是LOS_MEMBOX_INFO信息,接著是各個內(nèi)存塊,每塊內(nèi)存塊大小是uwBlkSize,包含內(nèi)存塊節(jié)點LOS_MEMBOX_NODE和內(nèi)存塊數(shù)據(jù)區(qū)??臻e內(nèi)存塊節(jié)點指向下一塊空閑內(nèi)存塊節(jié)點。

1.2 靜態(tài)內(nèi)存常用宏定義

靜態(tài)內(nèi)存頭文件中還提供了一些重要的宏定義。⑴處的LOS_MEMBOX_ALIGNED(memAddr)用于對齊內(nèi)存地址,⑵處OS_MEMBOX_NEXT(addr, blkSize)根據(jù)當(dāng)前節(jié)點內(nèi)存地址addr和內(nèi)存塊大小blkSize獲取下一個內(nèi)存塊的內(nèi)存地址。⑶處OS_MEMBOX_NODE_HEAD_SIZE表示內(nèi)存塊中節(jié)點頭大小,每個內(nèi)存塊包含內(nèi)存節(jié)點LOS_MEMBOX_NODE和存放業(yè)務(wù)的數(shù)據(jù)區(qū)。⑷處表示靜態(tài)內(nèi)存的總大小,包含內(nèi)存池信息結(jié)構(gòu)體占用的大小,和各個內(nèi)存塊占用的大小。

 
 
 
 
  1. ⑴  #define LOS_MEMBOX_ALIGNED(memAddr) (((UINTPTR)(memAddr) + sizeof(UINTPTR) - 1) & (~(sizeof(UINTPTR) - 1))) 
  2.  
  3. ⑵  #define OS_MEMBOX_NEXT(addr, blkSize) (LOS_MEMBOX_NODE *)(VOID *)((UINT8 *)(addr) + (blkSize)) 
  4.  
  5. ⑶  #define OS_MEMBOX_NODE_HEAD_SIZE sizeof(LOS_MEMBOX_NODE) 
  6.  
  7. ⑷  #define LOS_MEMBOX_SIZE(blkSize, blkNum) \ 
  8.     (sizeof(LOS_MEMBOX_INFO) + (LOS_MEMBOX_ALIGNED((blkSize) + OS_MEMBOX_NODE_HEAD_SIZE) * (blkNum))) 

 在文件kernel\src\mm\los_membox.c中也定義了一些宏和內(nèi)聯(lián)函數(shù)。⑴處定義OS_MEMBOX_MAGIC魔術(shù)字,這個32位的魔術(shù)字的后8位維護任務(wù)編號信息,任務(wù)編號位由⑵處的宏定義。⑶處宏定義任務(wù)編號的最大值,⑷處的宏從魔術(shù)字中提取任務(wù)編號信息。

⑸處內(nèi)聯(lián)函數(shù)設(shè)置魔術(shù)字,在內(nèi)存塊節(jié)點從靜態(tài)內(nèi)存池中分配出來后,節(jié)點指針.pstNext不再指向下一個空閑內(nèi)存塊節(jié)點,而是設(shè)置為魔術(shù)字。⑹處的內(nèi)聯(lián)函數(shù)用于校驗?zāi)g(shù)字。⑺處的宏根據(jù)內(nèi)存塊的節(jié)點地址獲取內(nèi)存塊的數(shù)據(jù)區(qū)地址,⑻處的宏根據(jù)內(nèi)存塊的數(shù)據(jù)區(qū)地址獲取內(nèi)存塊的節(jié)點地址。

 
 
 
 
  1. ⑴  #define OS_MEMBOX_MAGIC         0xa55a5a00 
  2.  
  3. ⑵  #define OS_MEMBOX_TASKID_BITS   8 
  4.  
  5. ⑶  #define OS_MEMBOX_MAX_TASKID    ((1 << OS_MEMBOX_TASKID_BITS) - 1) 
  6.  
  7. ⑷  #define OS_MEMBOX_TASKID_GET(addr) (((UINTPTR)(addr)) & OS_MEMBOX_MAX_TASKID) 
  8.  
  9. ⑸  STATIC INLINE VOID OsMemBoxSetMagic(LOS_MEMBOX_NODE *node) 
  10.     { 
  11.         UINT8 taskID = (UINT8)LOS_CurTaskIDGet(); 
  12.         node->pstNext = (LOS_MEMBOX_NODE *)(OS_MEMBOX_MAGIC | taskID); 
  13.     } 
  14.  
  15. ⑹  STATIC INLINE UINT32 OsMemBoxCheckMagic(LOS_MEMBOX_NODE *node) 
  16.     { 
  17.         UINT32 taskID = OS_MEMBOX_TASKID_GET(node->pstNext); 
  18.         if (taskID > (LOSCFG_BASE_CORE_TSK_LIMIT + 1)) { 
  19.             return LOS_NOK; 
  20.         } else { 
  21.             return (node->pstNext == (LOS_MEMBOX_NODE *)(OS_MEMBOX_MAGIC | taskID)) ? LOS_OK : LOS_NOK; 
  22.         } 
  23.     } 
  24.  
  25. ⑺  #define OS_MEMBOX_USER_ADDR(addr) \ 
  26.         ((VOID *)((UINT8 *)(addr) + OS_MEMBOX_NODE_HEAD_SIZE)) 
  27.  
  28. ⑻  #define OS_MEMBOX_NODE_ADDR(addr) \ 
  29.         ((LOS_MEMBOX_NODE *)(VOID *)((UINT8 *)(addr) - OS_MEMBOX_NODE_HEAD_SIZE)) 

 2、靜態(tài)內(nèi)存常用操作

當(dāng)用戶需要使用固定長度的內(nèi)存時,可以通過靜態(tài)內(nèi)存分配的方式獲取內(nèi)存,一旦使用完畢,通過靜態(tài)內(nèi)存釋放函數(shù)歸還所占用內(nèi)存,使之可以重復(fù)使用。

2.1 初始化靜態(tài)內(nèi)存池

我們分析下初始化靜態(tài)內(nèi)存池函數(shù)UINT32 LOS_MemboxInit(VOID *pool, UINT32 poolSize, UINT32 blkSize)的代碼。我們先看看函數(shù)參數(shù),VOID *pool是靜態(tài)內(nèi)存池的起始地址,UINT32 poolSize是初始化的靜態(tài)內(nèi)存池的總大小,poolSize需要小于等于*pool開始的內(nèi)存區(qū)域的大小,否則會影響后面的內(nèi)存區(qū)域。還需要大于靜態(tài)內(nèi)存的頭部大小sizeof(LOS_MEMBOX_INFO)。長度UINT32 blkSize是靜態(tài)內(nèi)存池中的每個內(nèi)存塊的塊大小。

我們看下代碼,⑴處對傳入?yún)?shù)進行校驗。⑵處設(shè)置靜態(tài)內(nèi)存池中每個內(nèi)存塊的實際大小,已內(nèi)存對齊,也算上內(nèi)存塊中節(jié)點信息。⑶處計算內(nèi)存池中內(nèi)存塊的總數(shù)量,然后設(shè)置已用內(nèi)存塊數(shù)量.uwBlkCnt為0。

⑷處如果可用的內(nèi)存塊為0,返回初始化失敗。⑸處獲取內(nèi)存池中的第一個空閑內(nèi)存塊節(jié)點。⑹處把空閑內(nèi)存塊掛載在靜態(tài)內(nèi)存池信息結(jié)構(gòu)體空閑內(nèi)存塊鏈表stFreeList.pstNext上,然后執(zhí)行⑺每個空閑內(nèi)存塊依次指向下一個空閑內(nèi)存塊,鏈接起來。

 
 
 
 
  1. UINT32 LOS_MemboxInit(VOID *pool, UINT32 poolSize, UINT32 blkSize) 
  2.     LOS_MEMBOX_INFO *boxInfo = (LOS_MEMBOX_INFO *)pool; 
  3.     LOS_MEMBOX_NODE *node = NULL; 
  4.     UINT32 index; 
  5.     UINT32 intSave; 
  6.  
  7. ⑴  if (pool == NULL) { 
  8.         return LOS_NOK; 
  9.     } 
  10.  
  11.     if (blkSize == 0) { 
  12.         return LOS_NOK; 
  13.     } 
  14.  
  15.     if (poolSize < sizeof(LOS_MEMBOX_INFO)) { 
  16.         return LOS_NOK; 
  17.     } 
  18.  
  19.     MEMBOX_LOCK(intSave); 
  20. ⑵  boxInfo->uwBlkSize = LOS_MEMBOX_ALIGNED(blkSize + OS_MEMBOX_NODE_HEAD_SIZE); 
  21.     if (boxInfo->uwBlkSize == 0) { 
  22.         MEMBOX_UNLOCK(intSave); 
  23.         return LOS_NOK; 
  24.     } 
  25. ⑶  boxInfo->uwBlkNum = (poolSize - sizeof(LOS_MEMBOX_INFO)) / boxInfo->uwBlkSize; 
  26.     boxInfo->uwBlkCnt = 0; 
  27. ⑷  if (boxInfo->uwBlkNum == 0) { 
  28.         MEMBOX_UNLOCK(intSave); 
  29.         return LOS_NOK; 
  30.     } 
  31.  
  32. ⑸  node = (LOS_MEMBOX_NODE *)(boxInfo + 1); 
  33.  
  34. ⑹  boxInfo->stFreeList.pstNext = node; 
  35.  
  36. ⑺  for (index = 0; index < boxInfo->uwBlkNum - 1; ++index) { 
  37.         node->pstNext = OS_MEMBOX_NEXT(node, boxInfo->uwBlkSize); 
  38.         node = node->pstNext; 
  39.     } 
  40.  
  41.     node->pstNext = NULL; 
  42.  
  43. #if (LOSCFG_PLATFORM_EXC == 1) 
  44.     OsMemBoxAdd(pool); 
  45. #endif 
  46.  
  47.     MEMBOX_UNLOCK(intSave); 
  48.  
  49.     return LOS_OK; 

 2.2 清除靜態(tài)內(nèi)存塊內(nèi)容

我們可以使用函數(shù)VOID LOS_MemboxClr(VOID *pool, VOID *box)來清除靜態(tài)內(nèi)存塊中的數(shù)據(jù)區(qū)內(nèi)容,需要2個參數(shù),VOID *pool是初始化過的靜態(tài)內(nèi)存池地址。VOID *box是需要清除內(nèi)容的靜態(tài)內(nèi)存塊的數(shù)據(jù)區(qū)的起始地址,注意這個不是內(nèi)存塊的節(jié)點地址,每個內(nèi)存塊的節(jié)點區(qū)不能清除。下面分析下源碼。

⑴處對參數(shù)進行校驗,⑵處調(diào)用memset_s()函數(shù)把內(nèi)存塊的數(shù)據(jù)區(qū)寫入0。寫入的開始地址是內(nèi)存塊的數(shù)據(jù)區(qū)的起始地址VOID *box,寫入長度是數(shù)據(jù)區(qū)的長度boxInfo->uwBlkSize - OS_MEMBOX_NODE_HEAD_SIZE。

 
 
 
 
  1. VOID LOS_MemboxClr(VOID *pool, VOID *box) 
  2.     LOS_MEMBOX_INFO *boxInfo = (LOS_MEMBOX_INFO *)pool; 
  3.  
  4. ⑴  if ((pool == NULL) || (box == NULL)) { 
  5.         return; 
  6.     } 
  7.  
  8. ⑵  (VOID)memset_s(box, (boxInfo->uwBlkSize - OS_MEMBOX_NODE_HEAD_SIZE), 0, 
  9.                    (boxInfo->uwBlkSize - OS_MEMBOX_NODE_HEAD_SIZE)); 

 2.3 申請、釋放靜態(tài)內(nèi)存

初始化靜態(tài)內(nèi)存池后,我們可以使用函數(shù)VOID *LOS_MemboxAlloc(VOID *pool)來申請靜態(tài)內(nèi)存,下面分析下源碼。

⑴處獲取靜態(tài)內(nèi)存池空閑內(nèi)存塊鏈表頭結(jié)點,如果鏈表不為空,執(zhí)行⑵,把下一個可用節(jié)點賦值給nodeTmp。⑶處把鏈表頭結(jié)點執(zhí)行下一個的下一個鏈表節(jié)點,然后執(zhí)行⑷把分配出來的內(nèi)存塊設(shè)置魔術(shù)字,接著把內(nèi)存池已用內(nèi)存塊數(shù)量加1。⑸處返回時調(diào)用宏OS_MEMBOX_USER_ADDR()計算出內(nèi)存塊的數(shù)據(jù)區(qū)域地質(zhì)。

 
 
 
 
  1. VOID *LOS_MemboxAlloc(VOID *pool) 
  2.     LOS_MEMBOX_INFO *boxInfo = (LOS_MEMBOX_INFO *)pool; 
  3.     LOS_MEMBOX_NODE *node = NULL; 
  4.     LOS_MEMBOX_NODE *nodeTmp = NULL; 
  5.     UINT32 intSave; 
  6.  
  7.     if (pool == NULL) { 
  8.         return NULL; 
  9.     } 
  10.  
  11.     MEMBOX_LOCK(intSave); 
  12. ⑴  node = &(boxInfo->stFreeList); 
  13.     if (node->pstNext != NULL) { 
  14. ⑵      nodeTmp = node->pstNext; 
  15. ⑶      node->pstNext = nodeTmp->pstNext; 
  16. ⑷      OsMemBoxSetMagic(nodeTmp); 
  17.         boxInfo->uwBlkCnt++; 
  18.     } 
  19.     MEMBOX_UNLOCK(intSave); 
  20.  
  21. ⑸  return (nodeTmp == NULL) ? NULL : OS_MEMBOX_USER_ADDR(nodeTmp); 

 對申請的內(nèi)存塊使用完畢,我們可以使用函數(shù)UINT32 LOS_MemboxFree(VOID *pool, VOID *box)來釋放靜態(tài)內(nèi)存,需要2個參數(shù),VOID *pool是初始化過的靜態(tài)內(nèi)存池地址。VOID *box是需要釋放的靜態(tài)內(nèi)存塊的數(shù)據(jù)區(qū)的起始地址,注意這個不是內(nèi)存塊的節(jié)點地址。下面分析下源碼。

⑴處根據(jù)待釋放的內(nèi)存塊的數(shù)據(jù)區(qū)域地址獲取節(jié)點地址node,⑵對要釋放的內(nèi)存塊先進行校驗。⑶處把要釋放的內(nèi)存塊掛在內(nèi)存池空閑內(nèi)存塊鏈表上,然后執(zhí)行⑷把已用數(shù)量減1。

 
 
 
 
  1. LITE_OS_SEC_TEXT UINT32 LOS_MemboxFree(VOID *pool, VOID *box) 
  2.     LOS_MEMBOX_INFO *boxInfo = (LOS_MEMBOX_INFO *)pool; 
  3.     UINT32 ret = LOS_NOK; 
  4.     UINT32 intSave; 
  5.  
  6.     if ((pool == NULL) || (box == NULL)) { 
  7.         return LOS_NOK; 
  8.     } 
  9.  
  10.     MEMBOX_LOCK(intSave); 
  11.     do { 
  12. ⑴      LOS_MEMBOX_NODE *node = OS_MEMBOX_NODE_ADDR(box); 
  13. ⑵      if (OsCheckBoxMem(boxInfo, node) != LOS_OK) { 
  14.             break; 
  15.         } 
  16.  
  17. ⑶      node->pstNext = boxInfo->stFreeList.pstNext; 
  18.         boxInfo->stFreeList.pstNext = node; 
  19. ⑷      boxInfo->uwBlkCnt--; 
  20.         ret = LOS_OK; 
  21.     } while (0); 
  22.     MEMBOX_UNLOCK(intSave); 
  23.  
  24.     return ret; 

 接下來,我們再看看校驗函數(shù)OsCheckBoxMem()。⑴如果內(nèi)存池的塊大小為0,返回校驗失敗。⑵處計算出要釋放的內(nèi)存快節(jié)點相對第一個內(nèi)存塊節(jié)點的偏移量offset。⑶如果偏移量除以內(nèi)存塊數(shù)量余數(shù)不為0,返回校驗失敗。⑷如果偏移量除以內(nèi)存塊數(shù)量的商大于等于內(nèi)存塊的數(shù)量,返回校驗失敗。⑸調(diào)用宏OsMemBoxCheckMagic校驗?zāi)g(shù)字。

 
 
 
 
  1. STATIC INLINE UINT32 OsCheckBoxMem(const LOS_MEMBOX_INFO *boxInfo, const VOID *node) 
  2.     UINT32 offset; 
  3.  
  4. ⑴  if (boxInfo->uwBlkSize == 0) { 
  5.         return LOS_NOK; 
  6.     } 
  7.  
  8. ⑵  offset = (UINT32)((UINTPTR)node - (UINTPTR)(boxInfo + 1)); 
  9. ⑶  if ((offset % boxInfo->uwBlkSize) != 0) { 
  10.         return LOS_NOK; 
  11.     } 
  12.  
  13. ⑷  if ((offset / boxInfo->uwBlkSize) >= boxInfo->uwBlkNum) { 
  14.         return LOS_NOK; 
  15.     } 
  16.  
  17. ⑸   return OsMemBoxCheckMagic((LOS_MEMBOX_NODE *)node); 

 小結(jié)

本文帶領(lǐng)大家一起剖析了鴻蒙輕內(nèi)核的靜態(tài)內(nèi)存模塊的源代碼,包含靜態(tài)內(nèi)存的結(jié)構(gòu)體、靜態(tài)內(nèi)存池初始化、靜態(tài)內(nèi)存申請、釋放、清除內(nèi)容等。后續(xù)也會陸續(xù)推出更多的分享文章,敬請期待。

想了解更多內(nèi)容,請訪問:

和華為官方合作共建的鴻蒙技術(shù)社區(qū)

https://harmonyos.


網(wǎng)站欄目:鴻蒙輕內(nèi)核M核源碼分析系列八靜態(tài)內(nèi)存MemoryBox
轉(zhuǎn)載來于:http://www.5511xx.com/article/cdsjgcj.html