首頁 > 軟體

SylixOS 定長記憶體管理

2020-06-16 17:12:53

1. 定長記憶體管理介紹

所謂定長記憶體,指的是使用者每次分配獲得的記憶體大小是相同的,即使用的是有確定長度的記憶體塊。同時,這些記憶體塊總的個數也是確定的,即整個記憶體總的大小也是確定的。這和通常理解的記憶體池的概念是一樣的。

使用定長記憶體管理的記憶體,有兩大優點:一是由於事先已經分配好了足夠的記憶體,可極大提高關鍵應用的穩定性;二是對於定長記憶體的管理通常有更為簡單的演算法,分配/釋放的效率更高。在 SylixOS 中,將管理的一個定長記憶體稱作 PARTITION,即記憶體分割區。

2. 定長記憶體管理設定

SylixOS可以通過API操作實現定長記憶體管理功能。

2.1      建立記憶體分割區

#include<SylixOS.h>

LW_OBJECT_HANDLE  Lw_Partition_Create(CPCHAR            pcName,

                                          PVOID              pvLowAddr,

                                          ULONG              ulBlockCounter,

                                          size_t            stBlockByteSize,

                                         ULONG              ulOption,

                                          LW_OBJECT_ID      *pulId)

函數Lw_Partition_Create 原型分析:

1.此函數成功時返回一個記憶體分割區控制代碼,失敗時返回LW_HANDLE_INVALID並設定錯誤號;

2.引數pcName指定該記憶體分割區的名稱,可以為LW_NULL(最大字長為32位元組);

3.引數pvLowAddr為使用者定義的一片記憶體的低地址,即起始地址。該地址必須滿足一個CPU字長的對齊,如在32位系統中,該地址必須4位元組對齊;

4.引數 ulBlockCounter 為該記憶體分割區的定長記憶體塊數量;

5.引數 stBlockByteSize 為記憶體塊的大小,必須不小於一個指標的長度,在32位系統中為4位元組;

6.引數ulOption為建立記憶體分割區的選項,如 2-1所示。

2-1  記憶體分割區建立選項

選項名稱

解釋

LW_OPTION_OBJECT_GLOBAL

表示該物件為一個核心全域性物件

LW_OPTION_OBJECT_LOCAL

表示該物件僅為一個進程擁有,即本地物件

LW_OPTION_DEFAULT

預設選項

7.輸出引數 pulId 儲存該記憶體分割區的 ID,與返回值相同。可以為 LW_NULL

 

註:驅動程式或核心模組才能使用LW_OPTION_OBJECT_GLOBAL 選項,對應的LW_OPTION_OBJECT_LOCAL 選項用於應用程式。為了使應用程式有更好的相容性,建議使用LW_OPTION_DEFAULT選項,該選項包含了 LW_OPTION_OBJECT_LOCAL 的屬性。

SylixOSLw_Partition_Create把已分配好的一塊大記憶體(pvLowAddr)通過一個PARTITION控制塊進行管理,PARTITION控制塊內容如程式清單 2-1所示。

程式清單2-1  PARTITION控制塊

/**********************************************************************************

  PARTITION 控制塊

**********************************************************************************/

typedefstruct {

    LW_LIST_MONO        PARTITION_monoResrcList;         /*  空閒資源表             */

    UINT8                PARTITION_ucType;                /*  型別標誌               */

    PLW_LIST_MONO        PARTITION_pmonoFreeBlockList/*  空閒記憶體塊表           */

    size_t              PARTITION_stBlockByteSize;      /*  每一塊的大小           */

                                                             /*  必須大於 sizeof(PVOID)*/

    ULONG                PARTITION_ulBlockCounter;        /*  塊數量                 */

    ULONG                PARTITION_ulFreeBlockCounter;    /*  空閒塊數量             */

    UINT16              PARTITION_usIndex;                /*  緩衝區索引            */ 

    CHAR                PARTITION_cPatitionName[LW_CFG_OBJECT_NAME_SIZE];

                                                             /*  名字                  */

    LW_SPINLOCK_DEFINE  (PARTITION_slLock);             /*  自旋鎖                */

} LW_CLASS_PARTITION;

Lw_Partition_Create對特定記憶體管理好後,會返回一個LW_OBJECT_HANDLE控制代碼。之後使用者需要對這塊記憶體進行獲取、釋放和刪除等,都可以通過這個控制代碼進行操作。

2.2      獲取/返還記憶體塊

PVOID  Lw_Partition_Get (LW_OBJECT_HANDLE  ulId)

PVOID  Lw_Partition_Put (LW_OBJECT_HANDLE  ulId, PVOID  pvBlock)

呼叫 Lw_Partition_Get 函數可以獲得一個記憶體分割區的記憶體塊,其大小為建立記憶體分割區時指定的大小,呼叫Lw_Partition_Put 函數將獲得的記憶體塊(Lw_Partition_Get 函數獲得)返回給記憶體分割區。

註:如果pvBlockNULL,則設定錯誤號為 ERROR_PARTITION_NULL

2.3      刪除記憶體分割區

ULONG  Lw_Partition_Delete (LW_OBJECT_HANDLE  *pulId)

ULONG  Lw_Partition_DeleteEx (LW_OBJECT_HANDLE  *pulId, BOOL  bForce)

如果一個記憶體分割區中有記憶體塊還在被使用,則理論上不應該立刻被刪除。如果bForce LW_TRUE,則 Lw_Partition_DeleteEx 忽略該條件直接刪除該分割區。通常情況下應用程式不應該使用該方式,這可能會導致記憶體錯誤。建議一般情況下使用 Lw_Partition_Delete 函數,它相當於下面呼叫,這樣避免釋放還在使用的記憶體。

Lw_Partition_DeleteEx(pulId, LW_FALSE);

3. 定長記憶體管理使用

比如程式需要建立一個連結串列,可以使用定長記憶體管理。如程式清單 3-1所示。

程式清單 3-1  程式程式碼

#include<stdio.h>

#include<SylixOS.h>

 

typedefstruct my_element {

    INTiValue;

} MY_ELEMENET;

 

#define   ELEMENT_MAX (8)

 

/*

 * _G_pucMyElementPool 的地址不滿足結構體 MY_ELEMENT 的對齊需求時,在有些硬體上,

 * 存取成員變數 iValue 將產生多位元組不對齊存取的錯誤(典型的硬體平台如 ARM)。

* 應該將_G_pucMyElementPool 的型別定義為UINT8,即單位元組存取,邏輯上它的起始地址可以是任  * 何對齊值。

 */

MY_ELEMENET_G_pmyelement[ELEMENT_MAX];

LW_STACK    _G_pucMyElementPool[sizeof(MY_ELEMENET) * ELEMENT_MAX /

                                   sizeof(LW_STACK)];        /*  申請一段記憶體空間    */

LW_HANDLE   _G_hMyPartition;                               /*  記憶體管理控制代碼         */                         

 

intmain(intargc, char *argv[])

{

    MY_ELEMENET *peleTable[ELEMENT_MAX]   = { LW_NULL };

    MY_ELEMENET *peleTmp                  = NULL;

    ULONG        ulError;

    INT          i                       = 0;

 

    _G_hMyPartition = Lw_Partition_Create("my_partition", _G_pucMyElementPool,

                                          ELEMENT_MAX, sizeof(MY_ELEMENET),

                                                LW_OPTION_DEFAULT,

                                                LW_NULL);

    if (_G_hMyPartition == LW_HANDLE_INVALID) {

        fprintf(stderr, "create partition failed.n");

        return (-1);

    }

    /*

     * 最多能夠獲得多少個元素記憶體

     */

    while (1) {

        peleTmp = (MY_ELEMENET *) Lw_Partition_Get(_G_hMyPartition);

        if (peleTmp != LW_NULL) {

            peleTable[i] = peleTmp;

            peleTmp->iValue = i;

            fprintf(stdout, "get element successfully, count = %d.n", i);

        } else {

            fprintf(stderr, "get element failed, count = %d.n", i);

            break;

        }

        i++;

    }

    /*

     * 在沒有全部回收元素記憶體的情況下刪除記憶體分割區

     */

ulError = Lw_Partition_Delete(&_G_hMyPartition); /*無法刪除還有未回收所有記憶體*/

    if (ulError != ERROR_NONE) {

        fprintf(stderr, "delete partition error.n");

    } else {

        return (0);

    }

    /*

     * 回收記憶體塊返回給記憶體分割區

     */

    for (i = 0; i < ELEMENT_MAX; i++) {

        peleTmp = peleTable[i];

        if (peleTmp != LW_NULL) {

            fprintf(stdout, "element%d value = %d.n", i, peleTmp->iValue);

            peleTmp = Lw_Partition_Put(_G_hMyPartition, peleTmp);

            if (peleTmp != LW_NULL) {

                fprintf(stderr, "element%d put failed.n", i);

            }

        } else {

            break;

        }

    }

    /*

     * 全部回收元素記憶體後刪除記憶體分割區

     */

    ulError = Lw_Partition_Delete(&_G_hMyPartition); /*   可以刪除記憶體分割區          */

    if (ulError != ERROR_NONE) {

        fprintf(stderr, "delete partition error.n");

        return (-1);

    } else {

        fprintf(stderr, "delete partition successfully.n");

    }

    return (0);

}

記憶體分割區不直接分配記憶體,它只是提供了一個管理記憶體的方法。因此在建立記憶體分割區時,需要指定需要管理的記憶體,該記憶體由使用的元素(即上面所述的記憶體塊)大小以及元素的最大個數決定。在程式清單 31中,建立了一個最大可以容納 8 個型別為MY_ELEMENT 物件的記憶體分割區,然後通過獲取元素物件、使用元素物件以及刪除記憶體分割區三方面展示了SylixOS 記憶體分割區的使用。該程式執行後,結果如下所示: 3-1所示。

3-1  程式執行結果

從執行結果可以看出,最大元素個數為8個,因此第9次獲取元素時會失敗。隨後使用Lw_Partition_Delete函數刪除記憶體分割區,由於此時元素還未被回收,因此刪除失敗。當回收完全部的元素後,才能成功刪除。

本文永久更新連結地址http://www.linuxidc.com/Linux/2017-06/144761.htm


IT145.com E-mail:sddin#qq.com