鴻蒙輕內核M核源碼分析系列九 動態內存Dynamic Memory 第三部分 非連續性內存

      網友投稿 912 2025-03-31

      鴻蒙輕內核M核源碼分析系列其他文章:

      鴻蒙輕內核源碼分析系列一 前言

      鴻蒙輕內核M核源碼分析系列二 數據結構-雙向循環鏈表

      鴻蒙輕內核M核源碼分析系列三 數據結構-任務就緒隊列

      鴻蒙輕內核M核源碼分析系列四 數據結構-任務排序鏈表

      鴻蒙輕內核M核源碼分析系列五 中斷Hwi

      鴻蒙輕內核M核源碼分析系列六 時間管理

      鴻蒙輕內核M核源碼分析系列七 任務及任務調度(1)任務棧

      鴻蒙輕內核M核源碼分析系列七 任務及任務調度(2)任務模塊

      鴻蒙輕內核M核源碼分析系列七 任務及任務調度 (3)任務調度模塊

      鴻蒙輕內核M核源碼分析系列八 靜態內存Static Memory

      鴻蒙輕內核M核源碼分析系列九 動態內存Dynamic Memory(1)

      鴻蒙輕內核M核源碼分析系列九 動態內存Dynamic Memory(2)

      鴻蒙輕內核M核源碼分析系列九 動態內存Dynamic Memory(3)

      鴻蒙輕內核M核源碼分析系列十 互斥鎖Mutex

      鴻蒙輕內核M核源碼分析系列十一 信號量Semaphore

      鴻蒙輕內核M核源碼分析系列十二 事件Event

      鴻蒙輕內核M核源碼分析系列十三 消息隊列Queue

      鴻蒙輕內核M核源碼分析系列十三(續) 消息隊列QueueMail接口

      鴻蒙輕內核M核源碼分析系列十四 軟件定時器Swtmr

      鴻蒙輕內核M核源碼分析系列十五 CPU使用率CPUP (1)

      鴻蒙輕內核M核源碼分析系列十五 CPU使用率CPUP (2)

      鴻蒙輕內核M核源碼分析系列九 動態內存Dynamic Memory 補充

      一些芯片片內RAM大小無法滿足要求,需要使用片外物理內存進行擴充。對于多段非連續性內存,需要內存管理模塊統一管理,應用使用內存接口時不需要關注內存分配屬于哪塊物理內存,不感知多塊內存。

      多段非連續性內存如下圖所示:

      鴻蒙輕內核M核新增支持了多段非連續性內存區域,把多個非連續性內存邏輯上合一,用戶不感知底層的不同內存塊。本文來分析下動態內存模塊的支持多段非連續內存的源碼,幫助讀者掌握其使用。本文中所涉及的源碼,以OpenHarmony LiteOS-M內核為例,均可以在開源站點https://gitee.com/openharmony/kernel_liteos_m 獲取。接下來,我們看下新增的結構體、宏和對外接口的源代碼。

      1、結構體定義和常用宏定義

      在文件kernel/include/los_memory.h中新增了結構體LosMemRegion用于維護多個非連續的內存區域,包含各個內存區域的開始地址和大小。如下:

      typedef struct { VOID *startAddress; /* 內存區域的開始地址 */ UINT32 length; /* 內存區域的長度 */ } LosMemRegion;

      需要注意這個結構體的定義需要開啟宏LOSCFG_MEM_MUL_REGIONS的情況下才生效,這個宏也是支持非連續內存區域的配置宏,定義在文件kernel/include/los_config.h中。

      我們繼續看下新增的幾個宏函數,定義在文件kernel/src/mm/los_memory.c,代碼下下文:

      注釋講的比較明白,當開啟LOSCFG_MEM_MUL_REGIONS支持非連續內存特性時,會把兩個不連續內存區域之間的間隔Gap區域標記為虛擬的已使用內存節點。這個節點當然不能被釋放,在內存調測特性中也不能被統計。因為我們只是把它視為已使用內存節點,但其實不是。在動態內存算法中每個內存節點都維護一個指向前序節點的指針,對于虛擬已使用節點,我們把該指針設置為魔術字,來標記它是個內存區域的間隔部分。

      ⑴處定義了一個魔術字OS_MEM_GAP_NODE_MAGIC,用于表示兩個不連續內存區域之前的間隔Gap區域。⑵和⑶處定義2個宏,分別用于設置魔術字,驗證魔術字。

      #if (LOSCFG_MEM_MUL_REGIONS == 1) /** * When LOSCFG_MEM_MUL_REGIONS is enabled to support multiple non-continuous memory regions, the gap between two memory regions * is marked as a used OsMemNodeHead node. The gap node could not be freed, and would also be skipped in some DFX functions. The * 'ptr.prev' pointer of this node is set to OS_MEM_GAP_NODE_MAGIC to identify that this is a gap node. */ ⑴ #define OS_MEM_GAP_NODE_MAGIC 0xDCBAABCD ⑵ #define OS_MEM_MARK_GAP_NODE(node) (((struct OsMemNodeHead *)(node))->ptr.prev = (struct OsMemNodeHead *)OS_MEM_GAP_NODE_MAGIC) ⑶ #define OS_MEM_IS_GAP_NODE(node) (((struct OsMemNodeHead *)(node))->ptr.prev == (struct OsMemNodeHead *)OS_MEM_GAP_NODE_MAGIC) #else ⑵ #define OS_MEM_MARK_GAP_NODE(node) ⑶ #define OS_MEM_IS_GAP_NODE(node) FALSE #endif

      2、動態內存常用操作

      本節我們一起分析下非連續性內存的實現算法,及接口實現代碼。首先通過示意圖了解下算法:

      集合示意圖,我們了解下非連續性內存合并為一個內存池的步驟:

      1、把多段內存區域的第一塊內存區域調用LOS_MemInit進行初始化

      2、獲取下一個內存區域的開始地址和長度,計算該內存區域和上一塊內存區域的間隔大小gapSize。

      3、把內存塊間隔部分視為虛擬的已使用節點,使用上一內存塊的尾節點,設置其大小為gapSize+ OS_MEM_NODE_HEAD_SIZE。

      4、把當前內存區域劃分為一個空閑內存塊和一個尾節點,把空閑內存塊插入到空閑鏈表。并設置各個節點的前后鏈接關系。

      5、有更多的非連續內存塊,重復上述步驟2-4。

      2.1 新增接口LOS_MemRegionsAdd

      新增的接口的接口說明文檔見下文,注釋比較詳細,總結如下:

      LOSCFG_MEM_MUL_REGIONS=0:

      不支持多段非連續內存,相關代碼不使能。

      LOSCFG_MEM_MUL_REGIONS=1:

      支持多段非連續內存,相關代碼使能。用戶配置多段內存區域,調用接口

      LOS_MemRegionsAdd(VOID *pool, const LosMemRegion * const multipleMemRegions)進行內存池合一:

      如果pool為空,則合并到主內存堆m_aucSysMem0。

      如果不為空,則初始化一個新的內存池,合并多內存區域為一個從堆。

      /** * @ingroup los_memory * @brief Initialize multiple non-continuous memory regions. * * @par Description: *

        *
      • This API is used to initialize multiple non-continuous memory regions. If the starting address of a pool is specified, * the memory regions will be linked to the pool as free nodes. Otherwise, the first memory region will be initialized as a * new pool, and the rest regions will be linked as free nodes to the new pool.
      • *
      * * @attention *
        *
      • If the starting address of a memory pool is specified, the start address of the non-continuous memory regions should be * greater than the end address of the memory pool.
      • *
      • The multiple non-continuous memory regions shouldn't conflict with each other.
      • *
      * * @param pool [IN] The memory pool address. If NULL is specified, the start address of first memory region will be * initialized as the memory pool address. If not NULL, it should be a valid address of a memory pool. * @param memRegions [IN] The LosMemRegion array that contains multiple non-continuous memory regions. The start address * of the memory regions are placed in ascending order. * @param memRegionCount [IN] The count of non-continuous memory regions, and it should be the length of the LosMemRegion array. * * @retval #LOS_NOK The multiple non-continuous memory regions fails to be initialized. * @retval #LOS_OK The multiple non-continuous memory regions is initialized successfully. * @par Dependency: *
        *
      • los_memory.h: the header file that contains the API declaration.
      • *
      * @see None. */ extern UINT32 LOS_MemRegionsAdd(VOID *pool, const LosMemRegion * const memRegions, UINT32 memRegionCount);

      2.1 新增接口LOS_MemRegionsAdd實現

      結合上文示意圖,加上注釋,實現比較清晰,直接閱讀下代碼即可。

      鴻蒙輕內核M核源碼分析系列九 動態內存Dynamic Memory 第三部分 非連續性內存

      #if (LOSCFG_MEM_MUL_REGIONS == 1) STATIC INLINE UINT32 OsMemMulRegionsParamCheck(VOID *pool, const LosMemRegion * const memRegions, UINT32 memRegionCount) { const LosMemRegion *memRegion = NULL; VOID *lastStartAddress = NULL; VOID *curStartAddress = NULL; UINT32 lastLength; UINT32 curLength; UINT32 regionCount; if ((pool != NULL) && (((struct OsMemPoolHead *)pool)->info.pool != pool)) { PRINT_ERR("wrong mem pool addr: %p, func: %s, line: %d\n", pool, __FUNCTION__, __LINE__); return LOS_NOK; } if (pool != NULL) { lastStartAddress = pool; lastLength = ((struct OsMemPoolHead *)pool)->info.totalSize; } memRegion = memRegions; regionCount = 0; while (regionCount < memRegionCount) { curStartAddress = memRegion->startAddress; curLength = memRegion->length; if ((curStartAddress == NULL) || (curLength == 0)) { PRINT_ERR("Memory address or length configured wrongly:address:0x%x, the length:0x%x\n", (UINTPTR)curStartAddress, curLength); return LOS_NOK; } if (((UINTPTR)curStartAddress & (OS_MEM_ALIGN_SIZE - 1)) || (curLength & (OS_MEM_ALIGN_SIZE - 1))) { PRINT_ERR("Memory address or length configured not aligned:address:0x%x, the length:0x%x, alignsize:%d\n", \ (UINTPTR)curStartAddress, curLength, OS_MEM_ALIGN_SIZE); return LOS_NOK; } if ((lastStartAddress != NULL) && (((UINT8 *)lastStartAddress + lastLength) >= (UINT8 *)curStartAddress)) { PRINT_ERR("Memory regions overlapped, the last start address:0x%x, the length:0x%x, the current start address:0x%x\n", \ (UINTPTR)lastStartAddress, lastLength, (UINTPTR)curStartAddress); return LOS_NOK; } memRegion++; regionCount++; lastStartAddress = curStartAddress; lastLength = curLength; } return LOS_OK; } STATIC INLINE VOID OsMemMulRegionsLink(struct OsMemPoolHead *poolHead, VOID *lastStartAddress, UINT32 lastLength, struct OsMemNodeHead *lastEndNode, const LosMemRegion *memRegion) { UINT32 curLength; UINT32 gapSize; struct OsMemNodeHead *curEndNode = NULL; struct OsMemNodeHead *curFreeNode = NULL; VOID *curStartAddress = NULL; curStartAddress = memRegion->startAddress; curLength = memRegion->length; // mark the gap between two regions as one used node gapSize = (UINT8 *)(curStartAddress) - ((UINT8 *)(lastStartAddress) + lastLength); lastEndNode->sizeAndFlag = gapSize + OS_MEM_NODE_HEAD_SIZE; OS_MEM_SET_MAGIC(lastEndNode); OS_MEM_NODE_SET_USED_FLAG(lastEndNode->sizeAndFlag); // mark the gap node with magic number OS_MEM_MARK_GAP_NODE(lastEndNode); poolHead->info.totalSize += (curLength + gapSize); poolHead->info.totalGapSize += gapSize; curFreeNode = (struct OsMemNodeHead *)curStartAddress; curFreeNode->sizeAndFlag = curLength - OS_MEM_NODE_HEAD_SIZE; curFreeNode->ptr.prev = lastEndNode; OS_MEM_SET_MAGIC(curFreeNode); OsMemFreeNodeAdd(poolHead, (struct OsMemFreeNodeHead *)curFreeNode); curEndNode = OS_MEM_END_NODE(curStartAddress, curLength); curEndNode->sizeAndFlag = 0; curEndNode->ptr.prev = curFreeNode; OS_MEM_SET_MAGIC(curEndNode); OS_MEM_NODE_SET_USED_FLAG(curEndNode->sizeAndFlag); #if (LOSCFG_MEM_WATERLINE == 1) poolHead->info.curUsedSize += OS_MEM_NODE_HEAD_SIZE; poolHead->info.waterLine = poolHead->info.curUsedSize; #endif } UINT32 LOS_MemRegionsAdd(VOID *pool, const LosMemRegion *const memRegions, UINT32 memRegionCount) { UINT32 ret; UINT32 lastLength; UINT32 curLength; UINT32 regionCount; struct OsMemPoolHead *poolHead = NULL; struct OsMemNodeHead *lastEndNode = NULL; struct OsMemNodeHead *firstFreeNode = NULL; const LosMemRegion *memRegion = NULL; VOID *lastStartAddress = NULL; VOID *curStartAddress = NULL; ret = OsMemMulRegionsParamCheck(pool, memRegions, memRegionCount); if (ret != LOS_OK) { return ret; } memRegion = memRegions; regionCount = 0; if (pool != NULL) { // add the memory regions to the specified memory pool poolHead = (struct OsMemPoolHead *)pool; lastStartAddress = pool; lastLength = poolHead->info.totalSize; } else { // initialize the memory pool with the first memory region lastStartAddress = memRegion->startAddress; lastLength = memRegion->length; poolHead = (struct OsMemPoolHead *)lastStartAddress; ret = LOS_MemInit(lastStartAddress, lastLength); if (ret != LOS_OK) { return ret; } memRegion++; regionCount++; } firstFreeNode = OS_MEM_FIRST_NODE(lastStartAddress); lastEndNode = OS_MEM_END_NODE(lastStartAddress, lastLength); while (regionCount < memRegionCount) { // traverse the rest memory regions, and initialize them as free nodes and link together curStartAddress = memRegion->startAddress; curLength = memRegion->length; OsMemMulRegionsLink(poolHead, lastStartAddress, lastLength, lastEndNode, memRegion); lastStartAddress = curStartAddress; lastLength = curLength; lastEndNode = OS_MEM_END_NODE(curStartAddress, curLength); memRegion++; regionCount++; } firstFreeNode->ptr.prev = lastEndNode; return ret; } #endif

      小結

      本文帶領大家一起剖析了鴻蒙輕內核M核的動態內存如何支持多段非連續性內存,包含結構體、運作示意圖、新增接口等等。感謝閱讀,如有任何問題、建議,都可以留言評論,謝謝。

      IoT 數據結構 虛擬化 輕量級操作系統 LiteOS

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:借用別人的幻燈片模板時如何去除WPS模板上的一些文字
      下一篇:excel中每個打印設置選項是什么意思?
      相關文章
      国产亚洲精品影视在线产品| 91丁香亚洲综合社区| 亚洲日韩精品国产一区二区三区| 亚洲精品国产情侣av在线| 亚洲精品福利视频| 亚洲不卡中文字幕无码| 久久夜色精品国产亚洲| 亚洲国产精品无码专区影院| 久久亚洲国产中v天仙www | 亚洲人成77777在线播放网站不卡 亚洲人成77777在线观看网 | 亚洲av中文无码| 亚洲成av人片在线观看天堂无码| 无码不卡亚洲成?人片| 亚洲av麻豆aⅴ无码电影| 亚洲国产精品一区二区九九| 亚洲国产精品第一区二区三区| 亚洲精品99久久久久中文字幕| 亚洲天堂免费在线视频| 国产亚洲精品线观看动态图| 国产亚洲美女精品久久久久狼| 久久精品国产亚洲av麻豆| 久久综合亚洲鲁鲁五月天| 亚洲自偷精品视频自拍| 亚洲图片中文字幕| 亚洲av无码一区二区三区观看| 亚洲一区二区无码偷拍| 亚洲AV无码一区二区三区鸳鸯影院| 久久水蜜桃亚洲AV无码精品| 亚洲AV无码乱码在线观看牲色 | 亚洲精品在线免费观看| 亚洲人成激情在线播放| 亚洲欧洲国产综合AV无码久久| 亚洲国产成人综合精品| 亚洲av日韩av欧v在线天堂| 久久久久久久亚洲精品| 亚洲av永久无码精品古装片| 亚洲黑人嫩小videos| 中文字幕亚洲情99在线| 亚洲av永久无码天堂网| 亚洲国产精品一区二区第四页 | 亚洲 综合 国产 欧洲 丝袜 |