在單片機芯片上,若是不考慮出廠固化的ROM空間的話,一般開發者能接觸到的存儲空間主要分兩種:掉電可保存數據的片內FLASH和掉電不可保存數據的片內RAM。
片內RAM(一般理解爲內存)的訪問速度比較快,能夠按照變量地址隨機訪問,但斷電後數據丟失。片內FLASH(一般理解爲硬盤)所保存的內容比較固定,主要用來保存程序自己的數據內容,保存的內容斷電不丟失。
對於單片機的片內RAM內存,主要有堆和棧之分,本章的內存管理,主要是基於堆內存管理進行開展的,在RT-Thread中,有兩種堆內存管理方式:動態內存堆管理和靜態內存池管理。
關於RT-Thread內存管理相關的內容,官方提供了比較豐富的文檔做爲參考,具體能夠查看如下連接:
https://www.rt-thread.org/doc...
本文嘗試從如下幾個方面總結一下RT-Thread內存管理的學習過程
內存管理相關介紹html
在運行操做系統的單片機上面,代碼和變量會佔用一部分固定的內存開銷,操做系統在初始化的時候,會去除掉這部分已經佔用的內存,把剩下的閒置內存歸入到系統堆裏面進行統一管理,不論是動態堆內存,仍是靜態內存池,都是使用這部分閒置空間的。
因爲在實時操做系統裏面對時間的要求十分嚴格,爲了保證內存分配的時候不影響系統的實時性,就須要確保分配內存的時間是肯定並可控的;而且在內存分配達到必定次數後,就不可避免地產生內存碎片;與此同時,嵌入式設備的內存資源相對有限,有些系統只有幾十KB內存,而有些系統則有幾十MB。
因此,爲了解決以上內存分配可能出現的問題,須要使用一些內存管理算法來進行這些內存分配管理,RT-Thread提供了兩種內存管理方式,分別是:動態內存堆管理和靜態內存池管理。
動態內存堆管理git
內存堆管理分配主要用於系統動態分配內存的場合,好比,咱們使用動態方式建立某些內核對象(如消息隊列,郵箱,信號量,等等)的時候,所使用到的內存空間就是動態內存堆。動態內存堆的意思是,要用多少,系統就分配多少給你,不用的時候,就要進行釋放,還給系統再進行統一管理。
關於動態內存堆的管理,主要有三種算法:小內存分配算法,slab算法,memheap算法。關於這三種管理算法的實現原理介紹,RT-Thread官方已經給出了比較詳細的解釋,這裏再也不重複論述。
github
須要注意的是,這三種內存管理算法,咱們只能經過menuconfig來配置系統內核,選擇其中一種內存管理方法,對於用戶的應用程序接口而言,這三種算法是透明的,也就是說提供給用戶的內存管理接口是相同的,只是算法的實現原理不一樣。
關於動態堆內存管理,操做系統提供瞭如下API接口函數,以下圖所示。
靜態內存池管理算法
在使用動態內存堆管理系統內存的時候,這種方式很是靈活和方便,想用內存的時候就向系統申請分配,不用的時候就釋放還給系統,但這種方式也存在必定的弊端。
主要是向系統申請內存的時候,都要遍歷一次空閒內存的鏈表,查找可用的內存塊,而後再分配給用戶,並且這種方式不可避免地會產生內存碎片,因此這種內存管理方式的效率不是很高。這是一種「用時間換空間」的內存管理方式。
爲了提升內存的分配效率,RT-Thread提供了靜態內存池管理的方式。靜態內存池就是系統把自身管理的內存預先劃分爲多個固定大小的內存塊,當用戶須要申請內存的時候,就從這些固定大小的內存塊裏面申請。
靜態內存池管理的方式,還支持線程掛起操做,當系統沒有內存塊可用時,線程就會掛起等待,直到能申請到可用的內存塊,這種特性能夠用作線程間同步。安全
關於靜態內存池的工做機制,以下圖所示。
多線程
RT-Thread提供瞭如下API函數接口,用於靜態內存池管理。
內存堆和內存池的應用示例函數
內存管理相關的應用示例,主要是爲了驗證動態內存堆管理和靜態內存池管理相關的API函數接口,這裏包含兩個示例,分別是內存堆管理示例和內存池管理示例。學習
示例源碼下載連接:
https://github.com/embediot/r...
https://gitee.com/embediot/rt...url
內存堆管理示例會建立一個動態的線程,這個線程會動態申請內存並釋放,每次申請更大的內存,當申請不到的時候就結束。例程中分配內存成功並打印信息;當試圖申請 65536 byte 即 64KB 內存時,因爲開發板的單片機 RAM 總大小隻有 64K,而可用 RAM 小於 64K,因此分配失敗。操作系統
內存池管理示例會建立一個靜態的內存池對象,2 個動態線程。一個線程會試圖從內存池中得到內存塊,另外一個線程釋放內存塊內存塊。總共初始化了 4096 /(80+4) = 48 個內存塊。
1.線程 1 申請了 48 個內存塊以後,此時內存塊已經被用完,須要其餘地方釋放才能再次申請;但此時,線程 1 以一直等待的方式又申請了 1 個,因爲沒法分配,因此線程 1 掛起;
2.線程 2 開始執行釋放內存的操做;當線程 2 釋放一個內存塊的時候,就有一個內存塊空閒出來,喚醒線程 1 申請內存,申請成功後再申請,線程 1 又掛起,再循環一次②;
3.線程 2 繼續釋放剩餘的內存塊,釋放完畢。
在memory_test.h頭文件裏面,經過打開相應的宏定義開關,從新編譯工程源碼,下載到開發板便可驗證明驗現象,以下圖所示。
內存管理相關注意事項
在使用RT-Thread內存管理相關接口的時候,爲了確保系統穩定性,有如下注意事項:
1.因爲系統爲了保證內存在多線程的狀態下能安全分配,引入了互斥操做,所以不能在中斷服務程序裏面分配或釋放內存塊,不然會引發當前線程被掛起。
2.在使用內存堆管理的時候,產生的內存碎片會在系統空閒線程運行的時候進行回收。
3.用戶應用程序在申請內存分配的時候,建議判斷是否申請成功,並對申請成功的內存空間進行初始化後再使用。
4.動態內存堆管理是一種「用時間換空間」的內存管理方式,這種方式能夠節省必定的內存空間,但會損失一點效率。
5.靜態內存池管理是一種「用空間換時間」的內存管理方式,這種方式相對來講比較高效,但會形成必定的空間浪費。
6.對於以KB爲單位的單片機片內RAM內存,通常採用動態內存堆裏面的小內存管理算法便可。