liteos內存(三)

2019-05-29     linux內核

1. 概述

1.1 基本概念

內存管理模塊管理系統的內存資源,它是作業系統的核心模塊之一。主要包括內存的初始化、分配以及釋放。

在系統運行過程中,內存管理模塊通過對內存的申請/釋放操作,來管理用戶和OS對內存的使用,使內存的利用率和使用效率達到最優,同時最大限度地解決系統的內存碎片問題。

Huawei LiteOS的內存管理分為靜態內存管理和動態內存管理,提供內存初始化、分配、釋放等功能。

  • 動態內存:在動態內存池中分配用戶指定大小的內存塊。
  • 優點:按需分配。
  • 缺點:內存池中可能出現碎片。
  • 靜態內存:在靜態內存池中分配用戶初始化時預設(固定)大小的內存塊。
  • 優點:分配和釋放效率高,靜態內存池中無碎片。
  • 缺點:只能申請到初始化預設大小的內存塊,不能按需申請。

1.2 動態內存運作機制

動態內存管理,即在內存資源充足的情況下,從系統配置的一塊比較大的連續內存(內存池),根據用戶需求,分配任意大小的內存塊。當用戶不需要該內存塊時,又可以釋放回系統供下一次使用。

與靜態內存相比,動態內存管理的好處是按需分配,缺點是內存池中容易出現碎片。

系統動態內存管理結構如圖1所示:

第一部分:堆內存(也稱內存池)的起始地址及堆區域總大小

第二部分:本身是一個數組,每個元素是一個雙向鍊表,所有free節點的控制頭都會被分類掛在這個數組的雙向鍊表中。

假設內存允許的最小節點為2min位元組,則數組的第一個雙向鍊表存儲的是所有size為2minmin+1的free節點,第二個雙向鍊表存儲的是所有size為2min+1min+2的free節點,依次類推第n個雙向鍊表存儲的是所有size為2min+n-1

第三部分:占用內存池極大部分的空間,是用於存放各節點的實際區域。以下是LOS_MEM_DYN_NODE節點結構體申明以及簡單介紹:

typedef struct tag LOS_MEM_DYN_NODE
{
LOS_DL_LIST stFreeNodeInfo;
struct tagLOS_MEM_DYN_NODE *pstPreNode;
UINT32 uwSizeAndFlag;
}LOS_MEM_DYN_NODE;

1.3 靜態內存運作機制

靜態內存實質上是一塊靜態數組,靜態內存池內的塊大小在初始化時設定,初始化後塊大小不可變更。

靜態內存池由一個控制塊和若干相同大小的內存塊構成。控制塊位於內存池頭部,用於內存塊管理。內存塊的申請和釋放以塊大小為粒度。

圖 3-4 靜態內存示意圖

2. 動態內存

2.1 開發指導

2.1.1 使用場景

內存管理的主要工作是動態的劃分並管理用戶分配好的內存區間。

動態內存管理主要是在用戶需要使用大小不等的內存塊的場景中使用。

當用戶需要分配內存時,可以通過作業系統的動態內存申請函數索取指定大小內存塊,一旦使用完畢,通過動態內存釋放函數歸還所占用內存,使之可以重複使用。

2.1.2 功能

Huawei LiteOS系統中的動態內存管理模塊為用戶提供下面幾種功能,具體的API詳見接口手冊。

2.1.3 開發流程

  1. 配置:
  • OS_SYS_MEM_ADDR:系統動態內存池起始地址,一般不需要修改
  • OS_SYS_MEM_SIZE:系統動態內存池大小,以byte為單位,系統默認分配DDR後未使用的空間
  • LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK:內存越界檢測開關,默認關閉。打開後,每次申請動態內存時執行動態內存塊越界檢查;每次釋放靜態內存時執行靜態內存塊越界檢查。
  1. 初始化LOS_MemInit。

初始一個內存池後如圖,生成一個 EndNode,並且剩餘的內存全部被標記為FreeNode節點。註: EndNode作為內存池末尾的節點, size為0。

  1. 申請任意大小的動態內存LOS_MemAlloc。

判斷動態內存池中是否存在申請量大小的空間,若存在,則劃出一塊內存塊,以指針形式返回,若不存在,返回NULL。

調用三次LOS_MemAlloc函數可以創建三個節點,假設名稱分別為UsedA, UsedB,UsedC,大小分別為sizeA, sizeB, sizeC。因為剛初始化內存池的時候只有一個大的FreeNode,所以這些內存塊是從這個FreeNode中切割出來的。

當內存池中存在多個FreeNode的時候進行malloc,將會適配最合適大小的FreeNode。用來新建內存塊,減少內存碎片。若新建的內存塊不等於被使用的FreeNode的大小,則在新建內存塊後,多餘的內存又會被標記為一個新的FreeNode。

  1. 釋放動態內存LOS_MemFree。

回收內存塊,供下一次使用。

假設調用LOS_MemFree釋放內存塊UsedB,則會回收內存塊UsedB,並且將其標記為FreeNode

2.1.4 平台差異性

2.2 編程實例

2.2.1 實例描述

Huawei LiteOS運行期間,用戶需要頻繁的使用內存資源,而內存資源有限,必須確保將有限的內存資源分配給急需的程序,同時釋放不用的內存。

通過Huawei LiteOS內存管理模塊可以保證高效、正確的申請、釋放內存。

本實例執行以下步驟:

  1. 初始化一個動態內存池。
  2. 在動態內存池中申請一個內存塊。
  3. 使用這塊內存塊存放一個數據。
  4. 列印出存放在內存塊中的數據。
  5. 釋放掉這塊內存。

2.2.2 編程實例

VOID los_memory_test() {
UINT32 *p_num = NULL;
UINT32 uwRet;
uwRet = LOS_MemInit(m_aucSysMem0, 32);
if (LOS_OK == uwRet) {
dprintf("內存池初始化成功!\\n");
}
else {
dprintf("內存池初始化失敗!\\n");
return;
}
/*分配內存*/
p_num = (int*)LOS_MemAlloc(m_aucSysMem0, 4);
if (NULL == p_num) {
dprintf("內存分配失敗!\\n");
return;
}
dprintf("內存分配成功\\n");
/*賦值*/
*p_num = 828;
dprintf("*p_num = %d\\n", *p_num);
/*釋放內存*/
uwRet = LOS_MemFree(m_aucSysMem0, p_num);
if (LOS_OK == uwRet) {
dprintf("內存釋放成功!\\n");
}
else {
dprintf("內存釋放失敗!\\n");
}
return;
}

2.2.3 結果驗證

圖 3-5 結果顯示

3. 靜態內存

3.1 開發指導

當用戶需要使用固定長度的內存時,可以使用靜態內存分配的方式獲取內存,一旦使用完畢,通過靜態內存釋放函數歸還所占用內存,使之可以重複使用。

3.2 功能

Huawei LiteOS的靜態內存管理主要為用戶提供以下功能。

3.3 開發流程

本節介紹使用靜態內存的典型場景開發流程。

  1. 規劃一片內存區域作為靜態內存池。
  2. 調用LOS_MemboxInit接口。

系統內部將會初始化靜態內存池。將入參指定的內存區域分割為N塊(N值取決於 靜態內存總大小和塊大小),將所有內存塊掛到空閒鍊表,在內存起始處放置控 制頭。

  1. 調用LOS_MemboxAlloc接口。

系統內部將會從空閒鍊表中獲取第一個空閒塊,並返回該塊的用戶空間地址。

  1. 調用LOS_MemboxFree接口。

將該塊內存加入空閒塊鍊表。

  1. 調用LOS_MemboxClr接口。

系統內部清零靜態內存塊,將入參地址對應的內存塊清零

3.3 編程實例

Huawei LiteOS運行期間,用戶需要頻繁的使用內存資源,而內存資源有限,必須確保將有限的內存資源分配給急需的程序,同時釋放不用的內存。

通過內存管理模塊可以保證正確且高效的申請釋放內存。

本實例執行以下步驟:

  1. 初始化一個靜態內存池。
  2. 從靜態內存池中申請一塊靜態內存。
  3. 使用這塊內存塊存放一個數據。
  4. 列印出存放在內存塊中的數據。
  5. 清除內存塊中的數據。
  6. 釋放掉這塊內存;
VOID los_membox_test(void) {
UINT32 *p_num = NULL;
UINT32 uwBlkSize = 10, uwBoxSize = 100;
UINT32 uwRet;
UINT32 pBoxMem[1000];
uwRet = LOS_MemboxInit(&pBoxMem[0], uwBoxSize, uwBlkSize);
if (uwRet != LOS_OK)
{
dprintf("內存池初始化失敗!\\n");
return;
}
else {
dprintf("內存池初始化成功!\\n");
}
/*申請內存塊*/
p_num = (int*)LOS_MemboxAlloc(pBoxMem);
if (NULL == p_num) {
dprintf("內存分配失敗!\\n");
return;
}
dprintf("內存分配成功\\n");
/*賦值*/
*p_num = 828;
dprintf("*p_num = %d\\n", *p_num);
/*清除內存內容*/
LOS_MemboxClr(pBoxMem, p_num);
dprintf("清除內存內容成功\\n *p_num = %d\\n", *p_num);
/*釋放內存*/
uwRet = LOS_MemboxFree(pBoxMem, p_num);
if (LOS_OK == uwRet) {
dprintf("內存釋放成功!\\n");
}
else{
dprintf("內存釋放失敗!\\n");
}
return;

3.4 結果驗證

圖 3-6 結果顯示

文章來源: https://twgreatdaily.com/zh-cn/53KSp2wBvvf6VcSZlfpk.html