FreeRTOS如何檢測內存泄漏

在嵌入式系統中,內存資源通常非常有限,內存泄漏可能導致系統性能下降甚至崩潰。內存泄漏是指程序分配的內存未被正確釋放,逐漸耗盡可用內存。

FreeRTOS作為一種輕量級實時操作系統(RTOS),廣泛應用于資源受限的嵌入式設備,其內存管理機制為開發者提供了檢測和預防內存泄漏的工具和方法。

我們先聊一聊FreeRTOS內存管理機制。

FreeRTOS通過不同的堆實現管理動態內存分配,位于源代碼的portable/MemMang目錄下。

以下是五種堆實現及其特點:

由于heap_1.c不支持釋放,內存泄漏在傳統意義上不存在。因此,本文重點關注支持釋放的堆實現(heap_2.c、heap_3.c、heap_4.c和heap_5.c),因為這些實現中若分配的內存未被釋放,可能導致泄漏。

FreeRTOS提供兩個關鍵函數用于監控堆使用情況,幫助開發者檢測潛在的內存泄漏:

  • xPortGetFreeHeapSize:返回當前剩余堆大小(以字節為單位)。通過定期檢查此值,可以觀察堆使用趨勢。如果剩余堆大小持續下降且未穩定,可能表明存在內存泄漏。
  • xPortGetMinimumEverFreeHeapSize:返回自系統啟動以來剩余堆的最小值。此函數可幫助識別堆使用的高峰,判斷是否接近內存耗盡。

以下是一個監控任務,定期記錄堆使用情況:

void vMonitorHeapTask(void *pvParameters) {size_t xFreeHeapSize, xMinFreeHeapSize;for(;;) {xFreeHeapSize = xPortGetFreeHeapSize();xMinFreeHeapSize = xPortGetMinimumEverFreeHeapSize();printf("當前剩余堆: %u 字節, 歷史最小剩余堆: %u 字節\n", xFreeHeapSize, xMinFreeHeapSize);vTaskDelay(pdMS_TO_TICKS(1000)); // 每秒記錄一次}
}

FreeRTOS提供跟蹤宏(trace macros),允許開發者自定義記錄內核和應用程序事件的行為。

針對內存管理,traceMALLOC和traceFREE宏可用于跟蹤pvPortMalloc和vPortFree調用,幫助識別未釋放的內存塊。

在FreeRTOSConfig.h或應用代碼中,可以定義以下宏:

#define traceMALLOC(pvReturn, xSize) do { \TaskHandle_t xCurrentTask = xTaskGetCurrentTaskHandle(); \char *pcTaskName = pcTaskGetName(xCurrentTask); \printf("任務 %s 分配 %u 字節于地址 %p\n", pcTaskName, xSize, pvReturn); \
} while(0)#define traceFREE(pv, xSize) do { \printf("釋放地址 %p\n", pv); \
} while(0)

上述代碼使用printf僅為示例。在實際嵌入式系統中,可能需要將日志寫入緩沖區或通過串口輸出,具體取決于硬件支持。

通過檢查日志,開發者可以對比分配和釋放記錄,尋找未釋放的內存塊。例如,若某個地址在traceMALLOC中出現但未在traceFREE中出現,則可能是泄漏點。

通過修改heap_4.c的BlockLink_t結構,添加字段記錄分配任務的句柄或名稱。例如,Chris Hockuba的文章建議維護一個分配列表(如BlockLink_t* allocList[256]),記錄每個分配的內存塊及其所屬任務。

以下是簡化實現:

void vPortAddToList(BlockLink_t *pxBlock) {for (int i = 0; i < 256; i++) {if (allocList[i] == NULL) {allocList[i] = pxBlock;break;}}
}void vPortRmFromList(BlockLink_t *pxBlock) {for (int i = 0; i < 256; i++) {if (allocList[i] == pxBlock) {allocList[i] = NULL;break;}}
}

此方法需要深入理解FreeRTOS源碼,適合高級開發者。

內存泄漏有時與緩沖區溢出相關。可以在分配的內存塊首尾添加canary值(固定模式),定期檢查是否被覆蓋。例如,在pvPortMalloc中額外分配4字節用于尾部canary值,并在釋放時驗證。

若不希望修改堆實現,可以在應用層包裝pvPortMalloc和vPortFree,記錄分配信息:

typedef struct {void *pvAddress;size_t xSize;const char *pcTaskName;
} AllocationRecord;#define MAX_ALLOCATIONS 100
AllocationRecord xAllocations[MAX_ALLOCATIONS];
int xAllocationCount = 0;void *myMalloc(size_t xSize) {void *pvReturn = pvPortMalloc(xSize);if (pvReturn != NULL && xAllocationCount < MAX_ALLOCATIONS) {TaskHandle_t xCurrentTask = xTaskGetCurrentTaskHandle();char *pcTaskName = pcTaskGetName(xCurrentTask);xAllocations[xAllocationCount].pvAddress = pvReturn;xAllocations[xAllocationCount].xSize = xSize;xAllocations[xAllocationCount].pcTaskName = pcTaskName;xAllocationCount++;}return pvReturn;
}void myFree(void *pv) {for (int i = 0; i < xAllocationCount; i++) {if (xAllocations[i].pvAddress == pv) {xAllocations[i] = xAllocations[xAllocationCount - 1];xAllocationCount--;break;}}vPortFree(pv);
}void vPrintAllocations(void) {for (int i = 0; i < xAllocationCount; i++) {printf("任務 %s 分配 %u 字節于 %p\n", xAllocations[i].pcTaskName, xAllocations[i].xSize, xAllocations[i].pvAddress);}
}

此跟蹤器記錄每個分配的地址、大小和任務名稱,可通過vPrintAllocations檢查當前分配狀態。

最后,總結一下,為預防和檢測內存泄漏,建議遵循以下實踐:

  • 優先靜態分配:使用xTaskCreateStatic等靜態創建函數,避免動態分配風險。
  • 確保分配與釋放匹配:每次pvPortMalloc必須有對應的vPortFree。
  • 使用內存池:對于固定大小的分配,使用內存池可減少碎片和泄漏風險。
  • 定期監控堆:通過監控任務或工具定期檢查堆使用情況。
  • 代碼審查:在開發和測試階段審查內存分配代碼,確保邏輯正確。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/78964.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/78964.shtml
英文地址,請注明出處:http://en.pswp.cn/web/78964.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Mockoon 使用教程

文章目錄 一、簡介二、模擬接口1、Get2、Post 一、簡介 1、Mockoon 可以快速模擬API&#xff0c;無需遠程部署&#xff0c;無需帳戶&#xff0c;免費&#xff0c;跨平臺且開源&#xff0c;適合離線環境。 2、支持get、post、put、delete等所有格式。 二、模擬接口 1、Get 左…

如何進行APP安全加固

進行APP安全加固的關鍵在于代碼混淆、加密敏感數據、權限管理、漏洞掃描與修復。其中&#xff0c;代碼混淆能有效阻止逆向工程與篡改攻擊&#xff0c;提升應用的安全防護能力。通過混淆代碼&#xff0c;攻擊者難以輕易理解源代碼邏輯&#xff0c;從而降低被破解或攻擊的風險。 …

【C++】手搓一個STL風格的string容器

C string類的解析式高效實現 GitHub地址 有夢想的電信狗 1. 引言&#xff1a;字符串處理的復雜性 ? 在C標準庫中&#xff0c;string類作為最常用的容器之一&#xff0c;其內部實現復雜度遠超表面認知。本文將通過一個簡易仿照STL的string類的完整實現&#xff0c;揭示其設…

辰鰻科技朱越洋:緊扣時代契機,全力投身能源轉型戰略賽道

國家能源局于4月28日出臺的《關于促進能源領域民營經濟發展若干舉措的通知》&#xff08;以下簡稱《通知》&#xff09;&#xff0c;是繼2月民營企業座談會后深化能源領域市場化改革的關鍵政策&#xff0c;標志著民營經濟在“雙碳”目標引領下正式進入能源轉型的核心賽道。 自…

Vue實現不同網站之間的Cookie共享功能

前言 最近有小伙伴在聊天室中提到這么一個需求&#xff0c;就是說希望用戶在博客首頁中登錄了之后&#xff0c;可以跳轉到管理系統去發布文章。這個需求的話就涉及到了不同網站之間cookie共享的功能&#xff0c;那么咱們就來試著解決一下這個功能。 實現方式 1. 后端做中轉 …

在一臺服務器上通過 Nginx 配置實現不同子域名訪問靜態文件和后端服務

一、域名解析配置 要實現通過不同子域名訪問靜態文件和后端服務&#xff0c;首先需要進行域名解析。在域名注冊商或 DNS 服務商處&#xff0c;為你的兩個子域名 blog.xxx.com 和 api.xxx.com 配置 A 記錄或 CNAME 記錄。將它們的 A 記錄都指向你服務器的 IP 地址。例如&#x…

Opencv進階操作:圖像拼接

文章目錄 前言一、圖像拼接的原理1. 特征提取與匹配2. 圖像配準3. 圖像變換與投影4. 圖像融合5. 優化與后處理 二、圖像拼接的簡單實現&#xff08;案例實現&#xff09;1.引入庫2.定義cv_show()函數3.創建特征檢測函數detectAndDescribe()4.讀取拼接圖片5.計算圖片特征點及描述…

LLM 論文精讀(三)Demystifying Long Chain-of-Thought Reasoning in LLMs

這是一篇2025年發表在arxiv中的LLM領域論文&#xff0c;主要描述了長思維鏈 Long Chain-of-Thought 對LLM的影響&#xff0c;以及其可能的生成機制。通過大量的消融實驗證明了以下幾點&#xff1a; 與shot CoT 相比&#xff0c;long CoT 的 SFT 可以擴展到更高的性能上限&…

計算機網絡常識:緩存、長短連接 網絡初探、URL、客戶端與服務端、域名操作 tcp 三次握手 四次揮手

緩存&#xff1a; 緩存是對cpu&#xff0c;內存的一個節約&#xff1a;節約的是網絡帶寬資源 節約服務器的性能 資源的每次下載和請求都會造成服務器的一個壓力 減少網絡對資源拉取的延遲 這個就是瀏覽器緩存的一個好處 表示這個html頁面的返回是不要緩存的 忽略緩存 需要每次…

《構建社交應用用戶激勵引擎:React Native與Flutter實戰解析》

React Native憑借其與JavaScript和React的緊密聯系&#xff0c;為開發者提供了一個熟悉且靈活的開發環境。在構建用戶等級體系時&#xff0c;它能夠充分利用現有的前端開發知識和工具。通過將用戶在社交應用中的各種行為進行量化&#xff0c;比如發布動態的數量、點贊評論的次數…

接口自動化測試框架詳解(pytest+allure+aiohttp+ 用例自動生成)

&#x1f345; 點擊文末小卡片&#xff0c;免費獲取軟件測試全套資料&#xff0c;資料在手&#xff0c;漲薪更快 近期準備優先做接口測試的覆蓋&#xff0c;為此需要開發一個測試框架&#xff0c;經過思考&#xff0c;這次依然想做點兒不一樣的東西。 接口測試是比較講究效…

Linux-----文件系統

文件大家都知道&#xff0c;前面的我的博客課程也為大家解釋了關于文件的打開等&#xff0c;今天我們要談論的是 文件在沒被打開的時候在磁盤中的位置和找到它的方式。 畫圖為大家展示&#xff1a; 方便理解 我們從下面幾個方面入手&#xff1a; 1. 看看物理磁盤 2. 了解一…

C++ set替換vector進行優化

文章目錄 demo代碼解釋&#xff1a; 底層原理1. 二叉搜索樹基礎2. 紅黑樹的特性3. std::set 基于紅黑樹的實現優勢4. 插入操作5. 刪除操作6. 查找操作 demo #include <iostream> #include <set>int main() {// 創建一個存儲整數的std::setstd::set<int> myS…

如何巧妙解決 Too many connections 報錯?

1. 背景 在日常的 MySQL 運維中&#xff0c;難免會出現參數設置不合理&#xff0c;導致 MySQL 在使用過程中出現各種各樣的問題。 今天&#xff0c;我們就來講解一下 MySQL 運維中一種常見的問題&#xff1a;最大連接數設置不合理&#xff0c;一旦到了業務高峰期就會出現連接…

QT的布局和彈簧及其代碼解讀

this指的是真正的當前正在顯示的窗口 main函數&#xff1a; Widget w是生成了一個主窗口&#xff0c;QT Designer是在這個主窗口里塞組件 w.show()用來展示這個主窗口 頭文件&#xff1a; namespace Ui{class Widget;}中的class Widget和下面的class Widget不是一個東西 Ui…

《AI大模型應知應會100篇》第52篇:OpenAI API 使用指南與最佳實踐

第52篇&#xff1a;OpenAI API 使用指南與最佳實踐 &#x1f4cc; 摘要 本文將帶你從零開始掌握 OpenAI API 的核心使用方法&#xff0c;涵蓋從基礎調用到高級功能的完整實戰路徑。通過詳細的代碼示例、圖文解析和可運行的 Python 腳本&#xff0c;幫助你快速上手 GPT-3.5、GP…

C#學習7_面向對象:類、方法、修飾符

一、類 1class 1)定義類 訪問修飾符class 類名{ 字段 構造函數&#xff1a;特殊的方法&#xff08;用于初始化對象&#xff09; 屬性 方法... } eg: public class Person { // 字段 private string name; private int a…

湖北理元理律師事務所:債務優化中的“生活保障”方法論

債務危機往往伴隨生活質量驟降&#xff0c;如何在還款與生存間找到平衡點&#xff0c;成為債務優化的核心挑戰。湖北理元理律師事務所基于多年實務經驗&#xff0c;提出“雙軌并行”策略&#xff1a;法律減負與生活保障同步推進。 債務優化的“溫度法則” 1.生存資金預留機制…

Jetpack Compose與Kotlin UI開發革命

Jetpack Compose + Kotlin:Android UI 開發的革命 簡介 Jetpack Compose 是 Google 推出的現代 Android UI 工具包,結合 Kotlin 語言,徹底改變了傳統 Android 開發的模式。過去,開發者依賴 XML 布局和命令式編程(如 findViewById 和手動更新視圖),導致代碼冗長且易出錯…

基于pyqt的上位機開發

目錄 安裝依賴 功能包含 運行結果 安裝依賴 pip install pyqt5 pyqtgraph pyserial 功能包含 自動檢測串口設備&#xff0c;波特率選擇/連接斷開控制&#xff0c;數據發送/接收基礎框架&#xff0c;實時繪圖區域&#xff08;需配合數據解析&#xff09; ""&q…