鴻蒙の軽いカーネルの静的なメモリの使用を解析します。

11451 ワード

はじめに
メモリ管理モジュール管理システムのメモリリソースは、オペレーティングシステムのコアモジュールの一つであり、主にメモリの初期化、割り当て及びリリースを含む。
システム運転中、メモリ管理モジュールは、メモリの申請/リリースにより、ユーザとOSのメモリ使用を管理し、メモリの利用率と使用効率を最適化し、システムのメモリデフラグ問題を最大限に解決する。
鴻蒙光内核のメモリ管理は静的メモリ管理とダイナミックメモリ管理に分けられ、メモリ初期化、割り当て、リリースなどの機能を提供します。
ダイナミックメモリ:ダイナミックメモリメモリにユーザ指定サイズのメモリブロックを割り当てます。
  • 長所:必要に応じて分配する。
  • 欠点:メモリに破片が発生する可能性があります。
  • 静的メモリ:静的メモリには、ユーザ初期化時に予め設定(固定)されたサイズのメモリブロックが割り当てられます。
  • の利点:割り当てとリリースの効率が高く、静的メモリプールに破片がない。
  • 欠点:プリセットサイズのメモリブロックを初期化することしかできません。必要に応じて申請できません。
  • 本論文は主に鴻蒙の軽いカーネル静的メモリを分析し、後続のシリーズは引き続き動的メモリを分析する。静的メモリは実質的に静的な配列であり、静的メモリプール内のブロックサイズは初期化時に設定され、初期化後のブロックサイズは変更できない。静的メモリプールは、一つの制御ブロックといくつかの同じサイズのメモリブロックから構成される。制御ブロックはメモリブロックの頭にあり、メモリブロックの管理に用いられる。メモリブロックの申請とリリースはブロックサイズで粒径とする。
    本文は静的メモリモジュールのソースコードを分析して、読者が静的メモリの使用を把握するのを助けます。本論文のソースコードはOpenHarmony LiteOS-Mカーネルの例で、オープンソースサイトhttps://gitee.com/openharmony/kernel_lieos_mで取得できます。
    次に、静的メモリの構造体、静的メモリ初期化、静的メモリの一般的な動作のソースコードを見ます。
    二、静的メモリ構造体定義と一般的なマクロ定義
    2.1、静的メモリ構造体の定義
    静的メモリ構造体はファイルケネル\include\los_membox.hで定義します。ソースコードは以下の通りです。①で定義されているのは静的メモリノードLOS_です。MEMBOXNODE構造体、⑵で定義された静的メモリの構造体プール情報構造体はLOS_である。MEMBOXINFO、構造体メンバーの説明は注釈部分を参照してください。
    
    ⑴  typedef struct tagMEMBOX_NODE {
            struct tagMEMBOX_NODE *pstNext; /**<             ,          */
        } LOS_MEMBOX_NODE;
    
    ⑵  typedef struct LOS_MEMBOX_INFO {
            UINT32 uwBlkSize;               /**<             ,          */
            UINT32 uwBlkNum;                /**<              */
            UINT32 uwBlkCnt;                /**<                  */
        #if (LOSCFG_PLATFORM_EXC == 1)
            struct LOS_MEMBOX_INFO *nextMemBox; /**<            */
        #endif
            LOS_MEMBOX_NODE stFreeList;     /**<                 */
        } LOS_MEMBOX_INFO;
    静的メモリの使用については、以下のように説明します。静的メモリ領域のブロックに対して、頭部はLOS_です。MEMBOXINFO情報は、次に各メモリブロックであり、各ブロックのメモリブロックサイズはuwBlkSizeであり、メモリブロックノードLOS_を含む。MEMBOXNODEとメモリブロックデータエリアです。空きメモリブロックノードは次のブロック空きメモリブロックノードを指す。

    2.2、静的メモリの一般的なマクロ定義
    静的メモリヘッダファイルには、重要なマクロ定義もいくつか提供されています。(1)ところのLOS_MEMBOXALIGNED(memAddr)はメモリアドレスを揃えるために使われます。MEMBOXNEXTは、現在のノードのメモリアドレスaddrとメモリブロックサイズblkSizeから次のメモリブロックのメモリアドレスを取得します。(3)にOS_MEMBOXNODE_HEAD_SIZEはメモリブロックの中の節のうなずいた大きさを表し、各メモリブロックはメモリノードLOS_を含む。MEMBOXNODEと預かり業務のデータエリアです。(4)は、静的メモリの合計サイズを示し、メモリプール情報構造体の占有サイズと各メモリブロックの占有サイズを含む。
    
    ⑴  #define LOS_MEMBOX_ALIGNED(memAddr) (((UINTPTR)(memAddr) + sizeof(UINTPTR) - 1) & (~(sizeof(UINTPTR) - 1)))
    
    ⑵  #define OS_MEMBOX_NEXT(addr, blkSize) (LOS_MEMBOX_NODE *)(VOID *)((UINT8 *)(addr) + (blkSize))
    
    ⑶  #define OS_MEMBOX_NODE_HEAD_SIZE sizeof(LOS_MEMBOX_NODE)
    
    ⑷  #define LOS_MEMBOX_SIZE(blkSize, blkNum) \
        (sizeof(LOS_MEMBOX_INFO) + (LOS_MEMBOX_ALIGNED((blkSize) + OS_MEMBOX_NODE_HEAD_SIZE) * (blkNum)))
    ファイルのケネル\src\mm\los_mbox.cにはマクロとインライン関数もいくつか定義されています。①にOS_を定義するMEMBOXMAGICマジックワードは、この32ビットのマジックワードの後8ビットのメンテナンスタスク番号情報であり、タスク番号ビットは⑵のマクロで定義されています。(3)マクロはタスク番号の最大値を定義し、(4)のマクロはマジックワードからタスク番号情報を抽出する。
    これらの内連結関数にマジックワードを設定し、メモリブロックノードが静的メモリプールから割り当てられた後、ノードポインタ。putNextは次の空きメモリブロックノードを指すのではなく、マジックワードに設定されます。⑹のカーネル関数はマジックワードを検証するために使われます。≦マクロは、メモリブロックのノードアドレスからメモリブロックのデータエリアアドレスを取得し、≦のマクロはメモリブロックのデータエリアアドレスからメモリブロックのノードアドレスを取得する。
    
    ⑴  #define OS_MEMBOX_MAGIC         0xa55a5a00
    
    ⑵  #define OS_MEMBOX_TASKID_BITS   8
    
    ⑶  #define OS_MEMBOX_MAX_TASKID    ((1 << OS_MEMBOX_TASKID_BITS) - 1)
    
    ⑷  #define OS_MEMBOX_TASKID_GET(addr) (((UINTPTR)(addr)) & OS_MEMBOX_MAX_TASKID)
    
    ⑸  STATIC INLINE VOID OsMemBoxSetMagic(LOS_MEMBOX_NODE *node)
        {
            UINT8 taskID = (UINT8)LOS_CurTaskIDGet();
            node->pstNext = (LOS_MEMBOX_NODE *)(OS_MEMBOX_MAGIC | taskID);
        }
    
    ⑹  STATIC INLINE UINT32 OsMemBoxCheckMagic(LOS_MEMBOX_NODE *node)
        {
            UINT32 taskID = OS_MEMBOX_TASKID_GET(node->pstNext);
            if (taskID > (LOSCFG_BASE_CORE_TSK_LIMIT + 1)) {
                return LOS_NOK;
            } else {
                return (node->pstNext == (LOS_MEMBOX_NODE *)(OS_MEMBOX_MAGIC | taskID)) ? LOS_OK : LOS_NOK;
            }
        }
    
    ⑺  #define OS_MEMBOX_USER_ADDR(addr) \
            ((VOID *)((UINT8 *)(addr) + OS_MEMBOX_NODE_HEAD_SIZE))
    
    ⑻  #define OS_MEMBOX_NODE_ADDR(addr) \
            ((LOS_MEMBOX_NODE *)(VOID *)((UINT8 *)(addr) - OS_MEMBOX_NODE_HEAD_SIZE))
    三、静的メモリの一般的な操作
    ユーザが固定長さのメモリを使用する必要がある場合は、静的メモリ割り当てによりメモリを取得し、使用が完了すると、静的メモリ解放関数を介して占有メモリを返却し、繰り返し使用することができます。
    3.1、静的メモリを初期化する
    静的メモリプール関数UNT 32 LOS_を初期化するために解析した。MemboxInit(VOID*pool,UNT 32 poolSize,UNT 32 blkSize)のコードです。まず関数パラメータを見てみます。VOID*poolは静的メモリプールの開始アドレスです。UNT 32 poolSizeは初期化された静的メモリプールの総サイズです。poolSizeは*pool開始のメモリ領域の大きさより小さい必要があります。そうでないと後のメモリ領域に影響します。静的メモリよりも頭のサイズが大きい必要があります。MEMBOXINFO長さUNT 32 blkSizeは、静的メモリプール内の各メモリブロックのブロックサイズである。
    コードを見て、①から着信パラメータをチェックします。⑵静的メモリプールの各メモリブロックの実際のサイズを設定し、メモリが配置され、メモリブロックのノード情報も計算する。(3)メモリプールのメモリブロックの総数を計算し、使用済みメモリブロック数を設定します。uwBlkCntは0です。
    使用可能なメモリブロックが0の場合、初期化に失敗します。メモリプールの最初の空きメモリブロックノードを取得します。⑹においてアイドルメモリブロックを静的メモリプール情報構造体アイドルメモリブロックチェーンstFree List.pstNextにマウントし、その後、各空きメモリブロックを次の空きメモリブロックに順次指し示してリンクする。
    
    UINT32 LOS_MemboxInit(VOID *pool, UINT32 poolSize, UINT32 blkSize)
    {
        LOS_MEMBOX_INFO *boxInfo = (LOS_MEMBOX_INFO *)pool;
        LOS_MEMBOX_NODE *node = NULL;
        UINT32 index;
        UINT32 intSave;
    
    ⑴  if (pool == NULL) {
            return LOS_NOK;
        }
    
        if (blkSize == 0) {
            return LOS_NOK;
        }
    
        if (poolSize < sizeof(LOS_MEMBOX_INFO)) {
            return LOS_NOK;
        }
    
        MEMBOX_LOCK(intSave);
    ⑵  boxInfo->uwBlkSize = LOS_MEMBOX_ALIGNED(blkSize + OS_MEMBOX_NODE_HEAD_SIZE);
        if (boxInfo->uwBlkSize == 0) {
            MEMBOX_UNLOCK(intSave);
            return LOS_NOK;
        }
    ⑶  boxInfo->uwBlkNum = (poolSize - sizeof(LOS_MEMBOX_INFO)) / boxInfo->uwBlkSize;
        boxInfo->uwBlkCnt = 0;
    ⑷  if (boxInfo->uwBlkNum == 0) {
            MEMBOX_UNLOCK(intSave);
            return LOS_NOK;
        }
    
    ⑸  node = (LOS_MEMBOX_NODE *)(boxInfo + 1);
    
    ⑹  boxInfo->stFreeList.pstNext = node;
    
    ⑺  for (index = 0; index < boxInfo->uwBlkNum - 1; ++index) {
            node->pstNext = OS_MEMBOX_NEXT(node, boxInfo->uwBlkSize);
            node = node->pstNext;
        }
    
        node->pstNext = NULL;
    
    #if (LOSCFG_PLATFORM_EXC == 1)
        OsMemBoxAdd(pool);
    #endif
    
        MEMBOX_UNLOCK(intSave);
    
        return LOS_OK;
    }
    3.2、静的メモリブロックの内容をクリアする
    関数VOID LOS_を使用できます。Membox Clar(VOID*pool、VOID*box)は、静的メモリブロック内のデータ領域の内容をクリアするために、2つのパラメータが必要であり、VOID*poolは初期化された静的メモリプールアドレスである。VOID*boxは、コンテンツの静的なメモリブロックのデータエリアの先頭アドレスをクリアする必要があります。これはメモリブロックのノードアドレスではなく、メモリブロックのノード領域ごとにクリアできないので注意してください。ソースコードを分析します。
    (1)パラメータをチェックし、(2)でmemset_を呼び出します。s()関数は、メモリブロックのデータエリアを0に書き込みます。書き込みの開始アドレスは、メモリブロックのデータエリアの先頭アドレスVOID*boxであり、書き込み長はデータエリアの長さbox Info->uwBlkSize-OS_である。MEMBOXNODE_HEAD_SIZE
    
    VOID LOS_MemboxClr(VOID *pool, VOID *box)
    {
        LOS_MEMBOX_INFO *boxInfo = (LOS_MEMBOX_INFO *)pool;
    
    ⑴  if ((pool == NULL) || (box == NULL)) {
            return;
        }
    
    ⑵  (VOID)memset_s(box, (boxInfo->uwBlkSize - OS_MEMBOX_NODE_HEAD_SIZE), 0,
                       (boxInfo->uwBlkSize - OS_MEMBOX_NODE_HEAD_SIZE));
    }
    3.3、静的メモリの申請、解放
    静的メモリを初期化したら、関数VOID*LOS_を使用できます。MemboxAlloc(VOID*pool)は静的メモリを申請します。下の分析はソースコードです。
    (1)静的メモリプールの空きメモリブロックチェーンのヘッダの結点を取得し、もしチェーンテーブルが空でないなら、(2)を実行し、次の利用可能なノードをnodeTmpに値付けする。(3)チェーンの先頭を結点して次のチェーンノードを実行し、(4)割り当てられたメモリブロックをマジックワードに設定し、次にメモリプールをメモリブロックの数に1を加算します。1.3で戻るとマクロOS_を呼び出します。MEMBOXUSER_ADDR()はメモリブロックのデータエリア地質を計算します。
    
    VOID *LOS_MemboxAlloc(VOID *pool)
    {
        LOS_MEMBOX_INFO *boxInfo = (LOS_MEMBOX_INFO *)pool;
        LOS_MEMBOX_NODE *node = NULL;
        LOS_MEMBOX_NODE *nodeTmp = NULL;
        UINT32 intSave;
    
        if (pool == NULL) {
            return NULL;
        }
    
        MEMBOX_LOCK(intSave);
    ⑴  node = &(boxInfo->stFreeList);
        if (node->pstNext != NULL) {
    ⑵      nodeTmp = node->pstNext;
    ⑶      node->pstNext = nodeTmp->pstNext;
    ⑷      OsMemBoxSetMagic(nodeTmp);
            boxInfo->uwBlkCnt++;
        }
        MEMBOX_UNLOCK(intSave);
    
    ⑸  return (nodeTmp == NULL) ? NULL : OS_MEMBOX_USER_ADDR(nodeTmp);
    }
    アプリケーションのメモリブロックの使用が完了しました。関数UNT 32 LOS_を使用できます。MemboxFree(VOID*pool、VOID*box)は静的メモリをリリースするために必要な2つのパラメータであり、VOID*poolは初期化された静的メモリアドレスである。VOID*boxはリリースが必要な静的メモリブロックのデータエリアの先頭アドレスであり、これはメモリブロックのノードアドレスではないことに注意する。ソースコードを分析します。
    (1)釈放すべきメモリブロックのデータ領域アドレスに基づいてノードアドレスnodeを取得し、(2)リリースすべきメモリブロックを先にチェックする。(3)釈放するメモリブロックをメモリプールの空きメモリブロックチェーンにかけ、4 aを実行して使用量を1減らします。
    
    LITE_OS_SEC_TEXT UINT32 LOS_MemboxFree(VOID *pool, VOID *box)
    {
        LOS_MEMBOX_INFO *boxInfo = (LOS_MEMBOX_INFO *)pool;
        UINT32 ret = LOS_NOK;
        UINT32 intSave;
    
        if ((pool == NULL) || (box == NULL)) {
            return LOS_NOK;
        }
    
        MEMBOX_LOCK(intSave);
        do {
    ⑴      LOS_MEMBOX_NODE *node = OS_MEMBOX_NODE_ADDR(box);
    ⑵      if (OsCheckBoxMem(boxInfo, node) != LOS_OK) {
                break;
            }
    
    ⑶      node->pstNext = boxInfo->stFreeList.pstNext;
            boxInfo->stFreeList.pstNext = node;
    ⑷      boxInfo->uwBlkCnt--;
            ret = LOS_OK;
        } while (0);
        MEMBOX_UNLOCK(intSave);
    
        return ret;
    }
    次に、検査関数Os Check BoxMem()を見てみます。(1)メモリプールのブロックサイズが0の場合、検証に失敗します。⑵リリースするメモリの早いノードが、最初のメモリブロックノードに対してオフセット量offsetを計算する。(3)オフセット量が除外された場合、ブロック数の残りが0でない場合、チェックに戻ります。(4)オフセット量が内のブロックの数より大きい場合は、メモリブロックの数を返します。➊マクロOsMemBoxCheckMagicを呼び出してマジックワードをチェックします。
    
    STATIC INLINE UINT32 OsCheckBoxMem(const LOS_MEMBOX_INFO *boxInfo, const VOID *node)
    {
        UINT32 offset;
    
    ⑴  if (boxInfo->uwBlkSize == 0) {
            return LOS_NOK;
        }
    
    ⑵  offset = (UINT32)((UINTPTR)node - (UINTPTR)(boxInfo + 1));
    ⑶  if ((offset % boxInfo->uwBlkSize) != 0) {
            return LOS_NOK;
        }
    
    ⑷  if ((offset / boxInfo->uwBlkSize) >= boxInfo->uwBlkNum) {
            return LOS_NOK;
        }
    
    ⑸   return OsMemBoxCheckMagic((LOS_MEMBOX_NODE *)node);
    }
    四、結び
    本論文では、鴻蒙光カーネルの静的メモリモジュールのソースコードを解析し、静的メモリの構造体、静的メモリメモリの初期化、静的メモリアプリケーション、リリース、クリアコンテンツなどを含む。鴻蒙軽いカーネルコードボックスを見つけやすいように、https://gitee.com/openharmony/kernel_lieos_mへのアクセスを提案します。
    以上は鴻蒙の軽いカーネルの静的なメモリの使用の詳しい内容を解析して、もっと多い鴻蒙の軽いカーネルの静的なメモリの資料に関して私達のその他の関連している文章に注意して下さい!