一、配置過程
二、基本知識點
2.1 搶占優先級和響應優先級
在 FreeRTOS 中,任務的調度方式主要有 ??搶占式(Preemptive)?? 和 ??協作式(Cooperative)?? 兩種模式,它們的核心區別在于 ??任務如何釋放 CPU 控制權??,以及 ??調度器如何決定任務切換??。以下是詳細對比:
1.搶占式調度(Preemptive Scheduling)?
高優先級任務可立即搶占低優先級任務??,無需等待當前任務主動讓出 CPU。
依賴配置??:需在?FreeRTOSConfig.h
中啟用:
#define configUSE_PREEMPTION 1 // 啟用搶占式調度
#define configUSE_TIME_SLICING 1 // 可選:同優先級任務時間片輪轉
工作流程??
- 任務就緒??:當一個高優先級任務進入就緒狀態(如被創建、延遲結束、收到信號量等),調度器會??立即檢查??是否需要切換。
- ??搶占發生??:如果新就緒的任務優先級??高于當前任務??,CPU 會??立即切換??到高優先級任務。
- ??無需主動讓步??:即使當前任務未調用?
taskYIELD()
或?vTaskDelay()
,也會被強制打斷。
優點??
- ??實時性強??:高優先級任務能快速響應(適合中斷服務、緊急事件處理)。
- ??自動化調度??:開發者無需手動管理任務切換。
??缺點??
- ??資源競爭風險??:需注意優先級反轉(Priority?Inversion)問題(可通過互斥量優先級繼承解決)。
- ??上下文切換開銷??:頻繁搶占會增加?CPU?負載。
??2. 協作式調度(Cooperative Scheduling)?
特點??
- ??任務必須主動釋放?CPU??,否則會一直運行直到完成。
- ??依賴配置??:需在?FreeRTOSConfig.h中關閉搶占:
#define configUSE_PREEMPTION 0 // 關閉搶占式調度
工作流程??
- ??任務運行??:當前任務會一直占用?CPU,直到:
- 調用?taskYIELD()主動讓出?CPU。
- 調用阻塞?API(如?vTaskDelay(),?xQueueReceive())。
- ??調度器介入??:只有當任務主動放棄?CPU?時,調度器才會選擇??下一個最高優先級就緒任務??運行。
優點??
- ??確定性高??:任務切換完全由代碼控制,避免不可預知的搶占。
- ??資源競爭少??:無需頻繁處理共享數據的互斥問題(適合簡單系統)。
- ??低開銷??:減少上下文切換次數。
??缺點??
- ??實時性差??:高優先級任務可能因低優先級任務不釋放?CPU?而無法及時響應。
- ??開發者負擔??:需手動插入?taskYIELD(),否則可能導致低優先級任務“餓死”。
3.?如何選擇???
??選搶占式??:
- 需要快速響應中斷或高優先級事件(如傳感器數據處理)。
- 系統中有多個不同優先級的任務。
??選協作式??:
- 資源受限的裸機升級項目(減少調度復雜性)。
- 任務執行時間短且可預測(如串口協議解析)。
2.2 響應優先級和搶占優先級
1.?優先級的基本機制??
FreeRTOS?使用???單一的優先級數值??(通常為?0到?configMAX_PRIORITIES-1,默認最高優先級為?configMAX_PRIORITIES-1)來管理任務調度。
??數值越大,優先級越高??(例如優先級?3>?2)。
高優先級任務可??搶占??(Preempt)低優先級任務,無需等待當前任務主動釋放?CPU。
??2.?搶占優先級(Preemptive?Priority)??
??定義??:高優先級任務??立即搶占??低優先級任務的?CPU?使用權。
??表現??:
? ? ? ? ?如果任務?A(優先級?3)就緒,而當前運行的是任務?B(優先級?2),FreeRTOS?會??立即切換??到任務?A。
? ? ? ? 這是?FreeRTOS?默認的調度行為(需配置?configUSE_PREEMPTION=1)。
??關鍵點??:
? ? ? ?搶占是??自動的??,無需任務主動讓步(除非使用?taskYIELD())。確保高優先級任務能??實時響應??。
??3.?響應優先級(Response?Priority)??
??定義??:任務在??就緒狀態??下被調度的順序,完全由優先級決定。
??表現??:
當多個任務同時就緒時,調度器會選擇??優先級最高??的任務運行(即響應最快)。
例如:任務?A(優先級?3)和任務?B(優先級?2)同時就緒,任務?A?會優先被調度。
??關鍵點??:
“響應優先級”是搶占式調度的??結果??,而非獨立配置。
與“搶占優先級”是同一機制的兩個視角:
- ??搶占??:強調中斷當前任務的行為。
- ??響應??:強調任務被選中的順序。
FreeRTOS 中 “實時性” 的體現是什么:? ?搶占式:高優先級任務可打斷低優先級任務(只要高優先級任務就緒,立即執行),實時性強;
2.3?FreeRTOS 的任務狀態有哪些?狀態之間如何切換?
- 考察點:任務生命周期的理解(高頻基礎題)。
- 核心答點:5 種狀態 ——就緒(Ready)、運行(Running)、阻塞(Blocked)、掛起(Suspended)、刪除(Deleted);
- 切換邏輯:運行→就緒(被高優先級任務搶占)、運行→阻塞(調用?
vTaskDelay()
/ 等待信號量)、阻塞→就緒(延時到 / 信號量觸發)、就緒→運行(調度器選擇最高優先級就緒任務)、任意狀態→掛起(vTaskSuspend()
)、掛起→就緒(xTaskResume()
)。
2.4?FreeRTOS 的內核組成有哪些核心模塊
考察點:內核架構的整體認知。
核心答點:任務管理(創建 / 刪除 / 切換)、時間管理(定時器 / 延時)、同步與通信(信號量 / 隊列 / 事件組 / 互斥鎖)、內存管理(堆 / 棧分配)、中斷管理(臨界區 / 中斷安全 API)。
2.5?FreeRTOS 的 “臨界區” 是什么?如何保護臨界區?
考察點:中斷與任務的資源沖突解決邏輯。
核心答點:臨界區是 “不能被中斷打斷的代碼段”(如操作共享變量);
保護方式:
- 任務級:
taskENTER_CRITICAL()
?/?taskEXIT_CRITICAL()
(關閉任務調度,不關閉中斷); - 中斷級:
taskENTER_CRITICAL_FROM_ISR()
?/?taskEXIT_CRITICAL_FROM_ISR()
(關閉中斷,需在中斷服務函數中使用)。
2.6?詳細說明 FreeRTOS 的 “臨界區” 是什么?如何保護臨界區。
在 FreeRTOS 中,臨界區(Critical Section)?是指一段 “不允許被中斷或其他任務打斷” 的代碼段,通常用于操作共享資源(如全局變量、硬件寄存器、外設等),以防止多任務并發或中斷觸發導致的數據競爭和不一致問題。
1. 任務級臨界區保護(在任務中使用)
適用于任務代碼中需要保護的臨界區,核心是 “禁止任務調度器切換”(但不禁止中斷,僅禁止因任務調度導致的打斷)。
// 進入臨界區:禁止任務調度
taskENTER_CRITICAL();// 臨界區代碼(操作共享資源)
// ...// 退出臨界區:恢復任務調度
taskEXIT_CRITICAL();
工作原理:
taskENTER_CRITICAL()
?會關閉 FreeRTOS 調度器(通過禁止 PendSV 中斷,PendSV 是任務切換的觸發源),但不影響其他硬件中斷(如定時器、串口中斷);- 臨界區代碼執行期間,高優先級任務即使就緒也無法搶占當前任務;
taskEXIT_CRITICAL()
?會恢復調度器,若有高優先級任務就緒,會觸發任務切換。
注意事項:
- 臨界區代碼要盡可能短,避免影響系統實時性(高優先級任務會被阻塞等待);
- 不可嵌套調用(多次調用?
taskENTER_CRITICAL()
?需對應相同次數的?taskEXIT_CRITICAL()
,但不建議嵌套)。
2. 中斷級臨界區保護(在中斷服務程序中使用)
適用于中斷服務程序(ISR)中需要保護的臨界區,核心是 “暫時關閉中斷”(防止被更高優先級中斷打斷)。
// 進入臨界區:保存當前中斷狀態并關閉中斷
UBaseType_t uxSavedInterruptStatus;
uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();// 臨界區代碼(操作共享資源)
// ...// 退出臨界區:恢復中斷狀態
taskEXIT_CRITICAL_FROM_ISR(uxSavedInterruptStatus);
工作原理:
taskENTER_CRITICAL_FROM_ISR()
?會先保存當前的中斷使能狀態,再關閉全局中斷(通過修改 CPU 狀態寄存器,如 ARM 的 PRIMASK);- 臨界區代碼執行期間,所有中斷(無論優先級)都被禁止,確保代碼不被任何中斷打斷;
taskEXIT_CRITICAL_FROM_ISR()
?會恢復進入臨界區前的中斷狀態(避免誤關閉其他中斷)。
注意事項:
- 中斷中的臨界區必須極致簡短(微秒級),否則會嚴重影響系統對外部事件的響應(如丟失中斷);
- 必須使用返回值?
uxSavedInterruptStatus
?作為參數傳遞給退出函數,否則可能導致中斷無法恢復。
2.7? FreeRTOS?靜態創建和動態創建
在 FreeRTOS 中,任務創建主要有兩種方式:靜態創建和動態創建。這兩種方式各有特點,適用于不同的應用場景。
考察點:任務創建的兩種內存分配方式。
核心答點:兩種核心創建函數;
區別:
xTaskCreate()
:動態分配任務棧和控制塊(依賴 FreeRTOS 堆管理,無需用戶手動分配內存);xTaskCreateStatic()
:靜態分配(需用戶手動指定任務棧數組、控制塊變量,不依賴堆,適合內存受限場景)。
2.7 什么是 “空閑任務(Idle Task)”?它的作用是什么?
考察點:FreeRTOS 內核的基礎任務。
核心答點:空閑任務是 FreeRTOS 啟動調度器(vTaskStartScheduler()
)時自動創建的最低優先級(優先級 0)任務;
作用:
- 當無其他就緒任務時,CPU 執行空閑任務(避免 CPU 空轉);
- 回收 “動態創建且被刪除” 的任務的內存(需開啟?
configUSE_IDLE_HOOK
?配置空閑鉤子函數)。
2.8?FreeRTOS 中的信號量(Semaphore)有哪幾種類型?分別用在什么場景?
特性 | 二進制信號量(Binary Semaphore) | 計數信號量(Counting Semaphore) | 互斥信號量(Mutex) |
---|---|---|---|
值范圍 | 只能為?0 ?或?1 | 0 到最大計數(用戶定義) | 只能為?0 ?或?1 (類似二進制) |
核心用途 | 任務間 / 中斷 - 任務同步;簡單互斥 | 有限資源的并發訪問控制(如連接池) | 共享資源的互斥訪問(解決優先級反轉) |
所有權 | 無(任何任務可釋放) | 無(任何任務可釋放) | 有(只有持有者可釋放) |
優先級繼承 | 無 | 無 | 有(避免優先級反轉) |
創建函數 | xSemaphoreCreateBinary() | xSemaphoreCreateCounting() | xSemaphoreCreateMutex() |
典型初始值 | 同步場景為?0 ;互斥場景為?1 | 資源初始數量(如?5 ?表示 5 個資源) | 1 (資源空閑) |
1. 二進制信號量(Binary Semaphore)
適用場景:任務間同步、中斷與任務同步,或簡單互斥(無優先級繼承需求)。
示例:中斷與任務同步
#include "FreeRTOS.h"
#include "semphr.h"SemaphoreHandle_t xBinarySemaphore;// 初始化:創建二進制信號量(初始值為0)
void vSetup() {xBinarySemaphore = xSemaphoreCreateBinary();if (xBinarySemaphore != NULL) {// 創建任務xTaskCreate(vTaskHandleEvent, "HandleEvent", 128, NULL, 1, NULL);vTaskStartScheduler();}
}// 中斷服務程序:觸發時釋放信號量
void EXTI_IRQHandler() {BaseType_t xHigherPriorityTaskWoken = pdFALSE;// 清除中斷標志(硬件相關)EXTI_ClearFlag();// 從ISR中釋放信號量(必須用FromISR版本)xSemaphoreGiveFromISR(xBinarySemaphore, &xHigherPriorityTaskWoken);// 若需切換任務,請求調度portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}// 任務:等待中斷信號并處理
void vTaskHandleEvent(void *pvParam) {for (;;) {// 等待信號量(永久阻塞,直到中斷觸發)if (xSemaphoreTake(xBinarySemaphore, portMAX_DELAY) == pdPASS) {printf("處理中斷事件\n");}}
}
2. 計數信號量(Counting Semaphore)
適用場景:控制對有限數量資源的并發訪問(如允許 5 個任務同時使用某個資源)。
示例:控制 3 個串口資源的并發訪問
#include "FreeRTOS.h"
#include "semphr.h"SemaphoreHandle_t xCountingSemaphore;
#define MAX_SERIAL_PORT 3 // 最大串口數量// 初始化:創建計數信號量(初始值為3,表示3個可用資源)
void vSetup() {xCountingSemaphore = xSemaphoreCreateCounting(MAX_SERIAL_PORT, MAX_SERIAL_PORT);if (xCountingSemaphore != NULL) {// 創建5個任務競爭串口資源for (int i = 0; i < 5; i++) {xTaskCreate(vTaskUseSerial, "SerialTask", 128, (void*)i, 1, NULL);}vTaskStartScheduler();}
}// 任務:使用串口資源
void vTaskUseSerial(void *pvParam) {int taskId = (int)pvParam;for (;;) {// 嘗試獲取串口資源(最多等待100ms)if (xSemaphoreTake(xCountingSemaphore, pdMS_TO_TICKS(100)) == pdPASS) {printf("任務%d:獲取串口成功,開始傳輸數據\n", taskId);vTaskDelay(pdMS_TO_TICKS(500)); // 模擬數據傳輸printf("任務%d:釋放串口\n", taskId);xSemaphoreGive(xCountingSemaphore); // 釋放資源} else {printf("任務%d:獲取串口失敗,重試\n", taskId);}vTaskDelay(pdMS_TO_TICKS(100));}
}
3. 互斥信號量(Mutex)
適用場景:共享資源的互斥訪問,尤其適用于存在優先級差異的任務(解決優先級反轉問題)。
示例:保護共享內存的訪問
#include "FreeRTOS.h"
#include "semphr.h"SemaphoreHandle_t xMutex;
int g_sharedMemory = 0; // 共享資源// 初始化:創建互斥信號量(初始值為1,資源空閑)
void vSetup() {xMutex = xSemaphoreCreateMutex();if (xMutex != NULL) {// 創建3個不同優先級的任務xTaskCreate(vHighPriorityTask, "HighTask", 128, NULL, 3, NULL);xTaskCreate(vMediumPriorityTask, "MediumTask", 128, NULL, 2, NULL);xTaskCreate(vLowPriorityTask, "LowTask", 128, NULL, 1, NULL);vTaskStartScheduler();}
}// 低優先級任務:持有共享資源
void vLowPriorityTask(void *pvParam) {for (;;) {xSemaphoreTake(xMutex, portMAX_DELAY);printf("低優先級任務:持有共享資源\n");vTaskDelay(pdMS_TO_TICKS(2000)); // 長時間占用資源printf("低優先級任務:釋放共享資源\n");xSemaphoreGive(xMutex);vTaskDelay(pdMS_TO_TICKS(1000));}
}// 中優先級任務:頻繁運行(可能搶占低優先級任務)
void vMediumPriorityTask(void *pvParam) {for (;;) {printf("中優先級任務:運行中\n");vTaskDelay(pdMS_TO_TICKS(100));}
}// 高優先級任務:需要訪問共享資源
void vHighPriorityTask(void *pvParam) {for (;;) {printf("高優先級任務:等待共享資源\n");xSemaphoreTake(xMutex, portMAX_DELAY);printf("高優先級任務:訪問共享資源\n");xSemaphoreGive(xMutex);vTaskDelay(pdMS_TO_TICKS(1000));}
}
關鍵特性:當低優先級任務持有互斥鎖時,高優先級任務等待期間會觸發優先級繼承(低優先級任務臨時提升至與高優先級任務相同的優先級),避免中優先級任務搶占 CPU 導致的優先級反轉。
2.9?隊列(Queue)的作用是什么?它的核心特性有哪些?
1 隊列的核心特性
- 數據傳遞方式:采用拷貝傳遞(數據被復制到隊列緩沖區),而非指針傳遞,避免內存訪問沖突。
- 先進先出(FIFO):默認按入隊順序出隊,也可配置為優先級出隊(高優先級數據優先)。
- 多對多通信:多個任務 / 中斷可向同一隊列發送數據,多個任務可從同一隊列接收數據。
- 阻塞機制:發送 / 接收數據時可指定超時時間,無數據 / 空間時阻塞等待,提高 CPU 效率。
- 中斷安全:提供?
FromISR
?系列 API,支持從中斷服務程序(ISR)中操作隊列。
2. 隊列的關鍵概念
- 隊列長度:可存儲的最大數據項數量(創建時指定)。
- 數據項大小:每個數據項的字節數(創建時指定,所有數據項大小相同)。
- 隊頭 / 隊尾:數據入隊從隊尾添加,出隊從隊頭移除(FIFO 模式)。
- 阻塞超時:
- 發送時:隊列滿時,任務阻塞等待空間,超時后返回失敗。
- 接收時:隊列空時,任務阻塞等待數據,超時后返回失敗。
3. 代碼實例
任務間通過隊列傳遞數據
場景:TaskSender
?周期性產生數據并發送到隊列,TaskReceiver
?從隊列接收并處理數據。
#include "FreeRTOS.h"
#include "queue.h"
#include <stdio.h>// 定義隊列句柄
QueueHandle_t xDataQueue;// 發送任務:產生數據并發送到隊列
void vTaskSender(void *pvParameters) {int32_t lDataToSend = 0;BaseType_t xStatus;for (;;) {// 發送數據到隊列(隊尾),超時時間0(不阻塞)xStatus = xQueueSend(xDataQueue, &lDataToSend, 0);if (xStatus != pdPASS) {printf("隊列滿,發送失敗!\n");} else {printf("發送數據: %d\n", lDataToSend);lDataToSend++;}vTaskDelay(pdMS_TO_TICKS(500)); // 每500ms發送一次}
}// 接收任務:從隊列接收數據并處理
void vTaskReceiver(void *pvParameters) {int32_t lReceivedData;BaseType_t xStatus;for (;;) {// 從隊列接收數據,超時時間1000ms(等待1秒)xStatus = xQueueReceive(xDataQueue, &lReceivedData, pdMS_TO_TICKS(1000));if (xStatus == pdPASS) {printf("接收數據: %d\n", lReceivedData);} else {printf("1秒內未收到數據!\n");}}
}int main(void) {// 創建隊列:長度為5,每個數據項為int32_t(4字節)xDataQueue = xQueueCreate(5, sizeof(int32_t));if (xDataQueue != NULL) {// 創建發送和接收任務xTaskCreate(vTaskSender, "Sender", 128, NULL, 1, NULL);xTaskCreate(vTaskReceiver, "Receiver", 128, NULL, 2, NULL);// 啟動調度器vTaskStartScheduler();}// 若調度器啟動失敗,進入死循環for (;;);return 0;
}
中斷與任務通過隊列傳遞數據
場景:外部中斷觸發時,ISR 向隊列發送事件標志,任務從隊列接收并處理中斷事件。
#include "FreeRTOS.h"
#include "queue.h"
#include "stm32f4xx.h" // 以STM32為例,其他平臺需適配QueueHandle_t xInterruptQueue;// 初始化外部中斷(硬件相關)
void vInitInterrupt() {// 配置GPIO為輸入,使能外部中斷(省略具體硬件配置)NVIC_EnableIRQ(EXTI0_IRQn); // 使能EXTI0中斷
}// 中斷服務程序:向隊列發送事件
void EXTI0_IRQHandler(void) {BaseType_t xHigherPriorityTaskWoken = pdFALSE;uint32_t ulEvent = 1; // 事件標志(1表示中斷觸發)// 清除中斷標志EXTI_ClearITPendingBit(EXTI_Line0);// 從ISR發送數據到隊列(必須使用FromISR版本)xQueueSendFromISR(xInterruptQueue, &ulEvent, &xHigherPriorityTaskWoken);// 若有更高優先級任務被喚醒,請求任務切換portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}// 處理任務:接收中斷事件并處理
void vTaskInterruptHandler(void *pvParameters) {uint32_t ulReceivedEvent;BaseType_t xStatus;for (;;) {// 等待中斷事件(永久阻塞)xStatus = xQueueReceive(xInterruptQueue, &ulReceivedEvent, portMAX_DELAY);if (xStatus == pdPASS) {printf("收到中斷事件,執行處理邏輯\n");// 此處添加中斷事件的具體處理代碼}}
}int main(void) {// 創建隊列:長度為3,每個數據項為uint32_txInterruptQueue = xQueueCreate(3, sizeof(uint32_t));if (xInterruptQueue != NULL) {vInitInterrupt(); // 初始化中斷xTaskCreate(vTaskInterruptHandler, "IntHandler", 128, NULL, 1, NULL);vTaskStartScheduler();}for (;;);return 0;
}
優先級隊列(數據插隊)
場景:緊急數據通過?xQueueSendToFront()
?插入隊頭,優先被處理。
// 發送緊急數據(插入隊頭)
void vSendEmergencyData(int32_t lEmergencyData) {BaseType_t xStatus;// 緊急數據插入隊頭,確保優先處理xStatus = xQueueSendToFront(xDataQueue, &lEmergencyData, pdMS_TO_TICKS(100));if (xStatus == pdPASS) {printf("緊急數據 %d 已插入隊頭\n", lEmergencyData);}
}
2.10.?事件組(Event Group)的作用是什么?和信號量、隊列有什么區別?
核心特性
- 事件表示:使用一個 32 位無符號整數(
EventBits_t
)存儲事件,每個位代表一個獨立事件(bit0~bit31)。 - 邏輯觸發:任務可等待事件的 “邏輯與”(所有指定事件都發生)或 “邏輯或”(任一指定事件發生)。
- 事件持久性:事件發生后會保持置位狀態,直到被顯式清除(或任務讀取時自動清除)。
- 多任務等待:多個任務可同時等待同一事件組的不同事件組合。
- 中斷安全:支持從中斷服務程序(ISR)中設置事件位。
2.11 什么是 “任務通知(Task Notification)”?它相比隊列、信號量有什么優勢?
考察點:FreeRTOS 高效同步機制(較新特性)。
核心答點:任務通知是 FreeRTOS v8.2.0 后新增的機制,通過 “直接向任務發送通知” 實現同步 / 通信(每個任務有一個 32 位的通知值);
優勢:
- 更高效:無需創建隊列 / 信號量等內核對象,直接操作任務控制塊,減少內存開銷和 CPU 消耗;
- 靈活:支持多種通知類型(如設置值、遞增、覆蓋、脈沖等),可替代二進制信號量、計數信號量、隊列(單數據)等場景。
通知類型(Action)
發送通知時可指定對接收任務通知值的操作,共 8 種類型(通過?eAction
?參數設置),核心類型包括:
eNoAction
:僅發送通知,不修改通知值。eSetBits
:按位或操作(類似事件組的置位)。eIncrement
:通知值遞增(類似計數信號量)。eSetValueWithOverwrite
:直接覆蓋通知值(類似隊列發送,覆蓋模式)。
功能 | 任務中使用的 API | 中斷中使用的 API(ISR) |
---|---|---|
發送通知 | xTaskNotify() | xTaskNotifyFromISR() |
等待通知 | ulTaskNotifyTake() (簡化版) | - |
等待通知(高級) | xTaskNotifyWait() | - |
清除通知 | 無需單獨 API,xTaskNotifyWait() ?可清除 | - |
2.12 FreeRTOS 有哪幾種內存分配方案(堆管理方案)?分別有什么特點?
考察點:內存管理的核心方案(高頻基礎題)。
核心答點:5 種堆管理方案(定義在?heap_1.c
?~?heap_5.c
?中,用戶需選擇一個引入工程);
- 堆 1(heap_1):僅支持動態分配(
pvPortMalloc()
),不支持釋放(vPortFree()
),適合無需刪除任務 / 信號量的場景(簡單、安全); - 堆 2(heap_2):支持分配和釋放,采用 “最佳適配” 算法,但不合并相鄰空閑塊,易產生內存碎片;
- 堆 3(heap_3):封裝標準 C 庫的?
malloc()
?和?free()
,依賴編譯器的內存管理,可重入(適合有操作系統支持的場景); - 堆 4(heap_4):支持分配和釋放,采用 “最佳適配”+“空閑塊合并”,減少內存碎片,支持動態調整堆大小;
- 堆 5(heap_5):基于堆 4,支持 “非連續內存塊”(如將 RAM 分為多個區域,堆 5 可管理這些分散的內存),適合內存布局復雜的場景。