--- title: 'RTOS 內存管理' disqus: kyleAlien --- RTOS 內存管理 === ## OverView of Content [TOC] ## 概述 在 C 語言的記憶體分配我們常在說堆 (`Stack`) 、棧 (`Heap`); ### 堆棧 * 在裸機 (沒有 OS 系統) 下我們最關注的是記憶體的 Stack 而不是 Heap * 在有 OS 系統的場合下,我們不只關注 Stack 也關注 Heap,OS 管理的內存就是 Heap,會將內存統一進行管理 :::warning 這裡的 Heap 跟數據節的 Heap 沒關係 ::: ### RAM - Heap 堆 * 單純的運行程式是不需要 RAM 的,但只要有關於要儲存相關的行為,就需要使用 RAM (全局、局部變量都會使用) * OS 在初始化時就會根據系統狀況,來 **動態決定 `Heap 大小` & `分配位置`** (動態創建是消耗 CPU 運算資源的) :::info 這不包括於內存管理方案,內存管理方案晚點會說 ::: ### RTT 內存管理 * RTT 的內存管理主要有分為兩種方案 1. Heap 內存堆管理 2. Pool 內存池管理 ## 堆管理 內存堆管理的特點是 **容量小、方便、但消耗 CPU 資源**,RTT 中有三種方案 1. 小內存管理算法 2. SLAB 管理算法 3. Memheap 管理算法 :::danger * OS 內存管理由於相關到多 Thread 所以會使用 Lock 機制,所以記得 **不要在中斷的時候使用內存分配 API** > 在中段分配可能被鎖住 ::: ### 小內存管理算法 * 有點類似於 JVM 的標記清除,其 **特色也是方便、快速,但會產生內存碎片的問題**;每個內存區塊的創建重點如下 1. **添加管理用的數據 (前、後鏈結指向指針)** 2. **標記是否被使用的 Flag**:之後在需要回收內存時只需要把 Flag 清除,而不用真正釋放該記憶體區塊 (也就是 2 手使用) 3. **Magic number,在 RTT 中魔術數值為 `0x1EA0` 用來表示該內存區塊是 Heap 內存** > ![](https://i.imgur.com/20bqJH1.png) * 小內存管理算法 OS 也會依據 User 的使用來 **動態分配 Heap 的大小** > 綠色代表已使用區塊 > > ![](https://i.imgur.com/Hror5ah.png) :::success * 建議使用在內存空間小於 2M 的裝置上 (嵌入式裝置就很多) ::: ### SLAB 管理算法 * SLAB 算法的核心是 **==預分配==**:**將每個物件需要的結構在 OS Kernel 中串接成一個列表**,當有需要使用時,就可以直接從 列表中取用 (**空間換時間**) > 可以串接 Semaphore、Mutex、Mail Box... 等等 * RTT 中的 SLAB 分配器會將不同大小的內存用一個鏈表串接,把大小相同的內存用 LinkedList 結構串接,並將 Linked Header 放入 Array 進行管理 (**稱為 Zone array**) **Zone 中的元素就是每個元素列表的 Header element** > ![](https://i.imgur.com/qHDZkwF.png) ### Memheap 管理算法 * Memheap 用於管理多個堆,將沒有連接的堆連接再一起,讓其看起來是一整塊大的堆 > RTT 需開啟 `RT_USING_MEMHEAP_AS_HEAP` 宏定義 > ![](https://i.imgur.com/Iqb3DIW.png) ### RTT 內存堆 - API * RTT 內存堆管理是在 BSP 中設定好的,一般不需要修改,只需要使用的 RTT 提供的內存 API 即可 | 功能 | API | 說明 | | -------- | -------- | -------- | | 內存申請 | `rt_malloc` | 動態申請內存 | | 內存申請 | `rt_realloc` | 對已經分配的的內存空間進行調整 | | 內存申請 | `rt_calloc` | 動態申請內存 & 完成初始化為 0 | | 內存釋放 | `rt_free` | 釋放內存空間 | | Hook 設定 | `rt_malloc_sethook` | 設定申請內存空間時的 hook 函數 | | Hook 釋放 | `rt_free_sethook` | 移除申請內存空間時的 hook 函數 | ## 池管理 內存池管理的特點是,**使用空間換時間 (速度快、但空間大)**,特點如下 1. **內存切分許多相同大小的區塊**:有點類似於 SLAB 設計的概念 2. **支持 Thread 掛起**:內存棧分配來講,失敗就會直接返回,不過 內存池管理 **支持 Thread 掛起,直到申請到內存** > ![](https://i.imgur.com/EWiIMiF.png) :::info 當需要不同大小內存時,可以動態創建新的內存池,但 User 申請的內存大小固定 (這是與 SLAB 不同的點,SLAB 可以申請大小不同的內存) ::: ### RTT 內存池管理 - API * 由於 RTT 內存池可以動態創建,所以比起 `內存棧管理` 多個創建 & 移除的函數 | 功能 | API | 說明 | | -------- | -------- | -------- | | 創建 Pool | `rt_mp_create` | 創建 Memory pool,失敗時返回 `RT_NULL` | | 初始化 | `rt_mp_init` | 初始化 Memory pool | | 分配 | `rt_mp_alloc` | 動態、靜態分配記憶體對象 | | 釋放 | `rt_mp_free` | 釋放記憶體空間 | | 刪除 | `rt_mp_delete` | (動) 刪除 Memory pool | | 脫離 | `rt_mp_detach` | (靜) 刪除 Memory pool | ## 內存堆 & 內存池 - 區別 | 內存堆 | 內存池 | | -------- | -------- | | BSP 包中預先支持,不支持動態創建、刪除 | 支持動態創建、刪除 Memory Pool | | **可以任意調整內存大小** | **內存大小固定** | | 失敗直接返回 | 可以掛起,直到申請成功 | ## Appendix & FAQ :::info ::: ###### tags: `RTOS`