SylixOS 定長內存管理

1. 定長內存管理介紹

所謂定長內存,指的是用戶每次分配得到的內存大小是相同的,即便用的是有肯定長度的內存塊。同時,這些內存塊總的個數也是肯定的,即整個內存總的大小也是肯定的。這和一般理解的內存池的概念是同樣的。算法

使用定長內存管理的內存,有兩大優勢:一是因爲事先已經分配好了足夠的內存,可極大提升關鍵應用的穩定性;二是對於定長內存的管理一般有更爲簡單的算法,分配/釋放的效率更高。在SylixOS 中,將管理的一個定長內存稱做PARTITION,即內存分區。函數

2. 定長內存管理設置

SylixOS能夠經過API操做實現定長內存管理功能。spa

2.1     建立內存分區

#include<SylixOS.h>指針

LW_OBJECT_HANDLE Lw_Partition_Create(CPCHAR            pcName,對象

                                         PVOID             pvLowAddr,blog

                                         ULONG             ulBlockCounter,索引

                                         size_t            stBlockByteSize,進程

                                          ULONG             ulOption,內存

                                         LW_OBJECT_ID      *pulId)ci

函數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 的屬性。

SylixOS的Lw_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 函數得到)返回給內存分區。

注:若是pvBlock爲NULL,則設置錯誤號爲 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所示。

wKioL1k_1rbw6tMRAACbikiwjYc290.png

圖 3-1  程序運行結果

從運行結果能夠看出,最大元素個數爲8個,所以第9次獲取元素時會失敗。隨後使用Lw_Partition_Delete函數刪除內存分區,因爲此時元素還未被回收,所以刪除失敗。當回收徹底部的元素後,才能成功刪除。

相關文章
相關標籤/搜索