- 前言
- 一、malloc 函數(shù)簡介
- 二、malloc 之于單片機(jī)
- 2.1 malloc 函數(shù)申請的內(nèi)存在哪里?
- 2.2 用與不用malloc的區(qū)別
- 三、malloc可能遇到的問題
- 3.1 內(nèi)存碎片
- 3.2 內(nèi)存管理
- 四、結(jié)語(用還是不用?)
前言
最近更新 RT-Thread 專欄到了內(nèi)存管理的時(shí)候,想了想該怎么來說明這個(gè)內(nèi)存管理,實(shí)際上在平時(shí)使用STM32做一般產(chǎn)品的時(shí)候基本不會用到 malloc 函數(shù),即便是使用了操作系統(tǒng),在業(yè)務(wù)邏輯不復(fù)雜的情況下,還是用不上malloc。
但是每個(gè)嵌入式 RTOS 都會有自己的內(nèi)存管理方式,本文就來聊聊我對 malloc 函數(shù)在單片機(jī)程序設(shè)計(jì)中的一些看法。
本文并不是要說明在單片機(jī)中怎么使用 malloc函數(shù),而是根據(jù)博主自己的理解,從函數(shù)使用的根本上來分析需不需要使用,何時(shí)何地使用。
本文的探討是單片機(jī)領(lǐng)域,以 Cortex-M 系列內(nèi)核為例。
一、malloc 函數(shù)簡介
malloc的全稱是memory allocation,中文叫動(dòng)態(tài)內(nèi)存分配。
函數(shù)原型 void *malloc(unsigned int size)
,專業(yè)解釋還是套用百度百科:對于malloc函數(shù),應(yīng)該所有嵌入式工程師都知道,即便沒用過也都聽過,通過上面簡單的說明,也都能夠知道是干什么用的。
注意上面紅色框框部分,malloc開辟的是連續(xù)的空間,返回的是一個(gè)地址,當(dāng)內(nèi)存不使用,需要使用free()
函數(shù)釋放內(nèi)存。
二、malloc 之于單片機(jī)
在我們的單片機(jī)程序設(shè)計(jì)中,大都使用的C語言,當(dāng)然可以使用 malloc 函數(shù),但是有很多人并不能夠真正的理解它。
要理解單片機(jī)系統(tǒng)中的 malloc函數(shù) ,首先必須了解動(dòng)態(tài)分配的內(nèi)存是在什么地方呢!
2.1 malloc 函數(shù)申請的內(nèi)存在哪里?
也許大部分人知道在堆中!是的,在堆中沒錯(cuò)。
那么接著問題,堆在單片機(jī)的什么地方呢?具體地址是多少呢?
要了解這個(gè)問題,就得了解內(nèi)核的數(shù)據(jù)存儲方式,我們以常用的STM32為例,我在下面這篇博文詳細(xì)的介紹過STM32的內(nèi)存管理(如果不懂的建議先看一下這篇博文):
STM32的內(nèi)存管理相關(guān)(內(nèi)存架構(gòu),內(nèi)存管理,map文件分析)
先簡單了解下單片機(jī)的堆棧,文中有如下說明:
如果通過上面推薦的博文理解了內(nèi)存分配,那么我們就可以得到如下結(jié)論,可以知道 malloc 申請空間的準(zhǔn)確地址了:
2.2 用與不用malloc的區(qū)別
知道了malloc申請空間在單片機(jī)中的地址,我們再來看一下用于不用的區(qū)別。
一般在我們的設(shè)計(jì)中,函數(shù)中可能會初始化一些臨時(shí)變量,如果是一個(gè)數(shù)組,那么他也會申請一段內(nèi)存空間,我們通過一張圖來看看使用臨時(shí)變量與malloc 的區(qū)別:
解釋到這里,相信大家對在單片機(jī)上使用 malloc 有了一個(gè)更深的認(rèn)識。他所存放的空間與我們經(jīng)常局部變量的空間是不同,而且我們也知道了在什么位置。
至于單片機(jī)用還是不用 malloc函數(shù)?別急,我們還得往下面分析分析。
三、malloc可能遇到的問題
還是官方的百度百科里面介紹malloc的工作機(jī)制時(shí)候,有下面的說明:注意圖中畫紅色的部分,簡單解釋就是,使用 malloc 函數(shù)多了以后,會產(chǎn)生很多的內(nèi)存碎片,白白浪費(fèi)內(nèi)存。
3.1 內(nèi)存碎片
什么是內(nèi)存碎片是什么?
這種專業(yè)的術(shù)語還得靠萬能的百度(雖然百度百科的解釋針對的是大范圍的,但是對于單片機(jī)來說其實(shí)是一樣的):
系統(tǒng)中所有的不可用的空閑內(nèi)存就是內(nèi)存碎片。
那么 內(nèi)存碎片是什如何產(chǎn)生的?
在上圖中其實(shí)有碎片是如何產(chǎn)生的說明,內(nèi)部碎片是因?yàn)?a target="_blank">處理器的體系結(jié)構(gòu),需要字節(jié)對齊,比如我們在單片機(jī)中,常有4字節(jié)對齊,8字節(jié)對齊,不要說這個(gè)也不知道,我隨便打開一個(gè) STM32L051 的啟動(dòng)文件說明(GCC環(huán)境下的鏈接文件):
按照這個(gè)啟動(dòng)文件,我們也應(yīng)該能知道,堆棧內(nèi)存空間是需要8字節(jié)對齊的,那么我們在STM32上使用 malloc 分配的內(nèi)存空間是8字節(jié)對齊的,即便你用不上8個(gè)字節(jié),系統(tǒng)也會給你對齊補(bǔ)上。
說到這個(gè),正好了可以說明我們內(nèi)存碎片產(chǎn)生的第一種情況,內(nèi)部碎片的產(chǎn)生:那么外部碎片的產(chǎn)生,我們也可以用圖形來表示:
隨著內(nèi)存不斷被分配和釋放,整個(gè)內(nèi)存區(qū)域會產(chǎn)生越來越多的碎片,因?yàn)樵谑褂眠^程中,申請了一些內(nèi)存,其中一些釋放了,導(dǎo)致內(nèi)存空間中存在一些小的內(nèi)存塊,它們地址不連續(xù),不能夠作為一整塊的大內(nèi)存分配出去,系統(tǒng)中還有足夠的空閑內(nèi)存,但因?yàn)樗鼈兊刂凡⒎沁B續(xù),不能組成一塊連續(xù)的完整內(nèi)存塊,會使得程序不能申請到大的內(nèi)存。
在我們使用的單片機(jī)上,碎片產(chǎn)生問題尤為明顯,平時(shí)接觸不到,那是因?yàn)橐话銓W(xué)習(xí)測試不會遇到復(fù)雜的項(xiàng)目。
3.2 內(nèi)存管理
使用 malloc 會產(chǎn)生碎片,那么有什么辦法可以解決這個(gè)問題?
當(dāng)然是有的,那就是內(nèi)存管理。
內(nèi)存管理就是為了解決上面提到的內(nèi)存碎片問題,如何高效,快速的分配,并且在適當(dāng)?shù)臅r(shí)候釋放和回收內(nèi)存資源。
對于單片機(jī)來說,如果你有能力是可以自己設(shè)計(jì)內(nèi)存管理的方式。
如果使用嵌入式操作系統(tǒng)比如 FreeRTOS、RT-Thread 的話,他們內(nèi)核是自帶內(nèi)存管理的,本文并不會討論他們具體是如何內(nèi)存管理的,但是有必要了解一下操作系統(tǒng)的思路。
以 FreeRTOS 為例子說明:
在 FreeRTOS 中有一個(gè)宏定義configTOTAL_HEAP_SIZE
操作系統(tǒng)首先向系統(tǒng)申請了一塊大的內(nèi)存,這塊內(nèi)存內(nèi)存由操作系統(tǒng)自己的內(nèi)存管理方式,對于FreeRTOS而言有5種內(nèi)存管理方式:
我們在設(shè)計(jì)的時(shí)候可以自己選擇使用哪一種
對于申請的這塊內(nèi)存由操作系統(tǒng)自動(dòng)管理,F(xiàn)reeRTOS操作系統(tǒng)創(chuàng)建的任務(wù),任務(wù)棧使用的就是這一塊內(nèi)存,同時(shí)使用pvPortMalloc
函數(shù)申請動(dòng)態(tài)內(nèi)存,也會從這一塊內(nèi)存中分配,因?yàn)樗幸惶淄晟频膬?nèi)存管理方式,所以相對我們直接使用 malloc
來說,他能夠很好的處理系統(tǒng)內(nèi)存碎片的問題。
既然說到這里,額外的一個(gè)問題,就是 FreeRTOS configTOTAL_HEAP_SIZE
定義額這塊內(nèi)存處于單片機(jī)內(nèi)存那個(gè)部分呢?
這就可以看我的又一篇博文:嵌入式RTOS的 任務(wù)棧 和 系統(tǒng)棧
FreeRTOS申請的內(nèi)存是屬于.bss段的,位置如下圖所示:
對于單片機(jī)使用的嵌入式操作系統(tǒng)來說,他們有自己的內(nèi)存管理方式,也會提供對于的動(dòng)態(tài)內(nèi)存申請結(jié)構(gòu),這時(shí)候我們使用操作系統(tǒng)提供的 malloc 接口函數(shù),可以很好的避免內(nèi)存碎片的產(chǎn)生。
注意!!單片機(jī)用了有內(nèi)存管理的操作系統(tǒng),系統(tǒng)會提供對于的 API,比如 FreeRTOS 的 pvPortMalloc
函數(shù),RT-Thread 的 rt_malloc
函數(shù)。如果使用 C 庫的 malloc
,還是會從系統(tǒng)堆里面申請內(nèi)存!!
對于高端的單片機(jī),有 MMU(內(nèi)存管理單元) 模塊,比如 Cortex-A 系列,有了MMU就能跑linux,那么內(nèi)存管理也是必備。
四、結(jié)語(用還是不用?)
本文算是詳細(xì)分析了一下 malloc 函數(shù)在單片機(jī)上的使用效果,我們知道了 malloc 函數(shù)使用申請了內(nèi)存空間在哪里,我們也知道了內(nèi)存碎片是如何產(chǎn)生的。
回到我們最初的問題,單片機(jī)領(lǐng)域,用還是不用 malloc 函數(shù)?
看完文章這個(gè)問題估計(jì)都不需要我直接回答了:
從項(xiàng)目復(fù)雜程度來說:
如果跑裸機(jī) 做些小項(xiàng)目,如果沒有自己的內(nèi)存管理方式不是必要都不建議使用,同時(shí)為了節(jié)約內(nèi)存,可以把heap設(shè)置成很小(留一點(diǎn)給可能調(diào)用的C庫函數(shù)會用到)。
如果跑操作系統(tǒng),操作系統(tǒng)有完善的內(nèi)存管理,可以痛快的使用操作系統(tǒng)的malloc
接口函數(shù)。 但是如果做些小項(xiàng)目,也是可以不用的。
如果跑裸機(jī) 做些大項(xiàng)目???? 我個(gè)人不太建議……
從使用的芯片RAM大小來說:
如果你選用的芯片內(nèi)存比較小,10多K甚至幾K,還是用靜態(tài)內(nèi)存局部變量把,因?yàn)槟軌蚴褂眯?nèi)存的項(xiàng)目也不會太復(fù)雜,比如物聯(lián)網(wǎng)傳感器單品項(xiàng)目。
如果選用的芯片內(nèi)存比較大上了 MB, 那么還是可以嘗試使用 malloc 動(dòng)態(tài)內(nèi)存分配的,但是前提還是得有內(nèi)存管理。
但是最后還是得說一下,隨著現(xiàn)在的單片機(jī)發(fā)展,內(nèi)存越來越大,雖然單片機(jī)小項(xiàng)目不建議使用 malloc 函數(shù),但是我們上了操作系統(tǒng)以后,要學(xué)會去使用動(dòng)態(tài)內(nèi)存分配,因?yàn)楫?dāng)以后做的項(xiàng)目越來越復(fù)雜,線程越來越多,我們定義的局部變量越來越多,即便我們可以繼續(xù)增大系統(tǒng) 棧 的大小,但是這終究不是一種合理的解決方式。我們應(yīng)該要學(xué)會合理的使用動(dòng)態(tài)內(nèi)存申請,為了以后向更高的地方前進(jìn) ~
沒有必要鉆牛角尖,如果項(xiàng)目簡單但就是想用。比如我就一個(gè)函數(shù)使用malloc 申請動(dòng)態(tài)內(nèi)存,沒有內(nèi)存管理,我就是用了怎么地? 這種情況用不用都一樣,看自己高興,沒有必要糾結(jié)!
-
單片機(jī)
+關(guān)注
關(guān)注
6059文章
44828瀏覽量
645026 -
嵌入式
+關(guān)注
關(guān)注
5126文章
19446瀏覽量
313377 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4365瀏覽量
63914 -
RTOS
+關(guān)注
關(guān)注
24文章
837瀏覽量
120610 -
malloc
+關(guān)注
關(guān)注
0文章
53瀏覽量
167
發(fā)布評論請先 登錄
在Keil Arm中使用malloc函數(shù)的方法是什么?
如何在單片機(jī)上也可正常使用動(dòng)態(tài)內(nèi)存分配
在AVR單片機(jī)中使用printf函數(shù)
怎樣去解決單片機(jī)使用malloc產(chǎn)生內(nèi)存泄露的問題呢
如何使用單片機(jī)系統(tǒng)重寫printf函數(shù)

分享可應(yīng)用于單片機(jī)的內(nèi)存管理模塊mem_malloc

單片機(jī) keil c語言字符比較函數(shù)的使用 使用strcmp();

記錄單片機(jī)使用malloc產(chǎn)生內(nèi)存泄露的問題及解決方法

如何在Vitis HLS GUI中使用庫函數(shù)?

評論