---
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 內存**
> 
* 小內存管理算法 OS 也會依據 User 的使用來 **動態分配 Heap 的大小**
> 綠色代表已使用區塊
>
> 
:::success
* 建議使用在內存空間小於 2M 的裝置上 (嵌入式裝置就很多)
:::
### SLAB 管理算法
* SLAB 算法的核心是 **==預分配==**:**將每個物件需要的結構在 OS Kernel 中串接成一個列表**,當有需要使用時,就可以直接從 列表中取用 (**空間換時間**)
> 可以串接 Semaphore、Mutex、Mail Box... 等等
* RTT 中的 SLAB 分配器會將不同大小的內存用一個鏈表串接,把大小相同的內存用 LinkedList 結構串接,並將 Linked Header 放入 Array 進行管理 (**稱為 Zone array**)
**Zone 中的元素就是每個元素列表的 Header element**
> 
### Memheap 管理算法
* Memheap 用於管理多個堆,將沒有連接的堆連接再一起,讓其看起來是一整塊大的堆
> RTT 需開啟 `RT_USING_MEMHEAP_AS_HEAP` 宏定義
> 
### 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 掛起,直到申請到內存**
> 
:::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`