做單片機研發(fā)前幾年,一直沒用過動態(tài)內(nèi)存分配的功能,但是如果想成為軟件架構(gòu)設(shè)計師,這是繞不過的一道坎。
其實單片機很少使用c標準庫自帶的malloc()函數(shù)去動態(tài)分配內(nèi)存,除非,你看老板不爽...
因為有缺陷,文章后面會提及。
一般是工程師借助現(xiàn)成的參考代碼,然后重新設(shè)計內(nèi)存管理代碼,改進動態(tài)內(nèi)存分配算法。
不過代碼難度挺大,c語言功底不好的,看到代碼會失聲痛哭....
不信?我裝個逼給你看!
下圖,是以前自己借鑒(抄襲),再吃透,后改進的內(nèi)存管理代碼,測試已解決內(nèi)存碎片問題。
代碼沒多少,卻讓我充分感受到,編程語言只是工具,編程思維才是靈魂。
本來是計劃用在無際單片機特訓(xùn)營項目6的,但是感覺太復(fù)雜了,怕老鐵們學(xué)著學(xué)著來罵我,所以這代碼就失寵了。
新手,或者有些一直從事比較簡單產(chǎn)品的工程師,可能無法理解,malloc的應(yīng)用場景,到底在哪里?
我以無際單片機特訓(xùn)營項目3來舉例幾個使用場景,或許你就明白了。
1.malloc使用場景1:動態(tài)任務(wù)創(chuàng)建
學(xué)過我們項目3的老鐵,不知道有沒有發(fā)現(xiàn)一個問題。
在用我們那個"小系統(tǒng)"創(chuàng)建任務(wù)的時候,不夠靈活,每次增加新的任務(wù),要手動在頭文件增加任務(wù)ID。
這樣做的目的,是為了給下面這個任務(wù)結(jié)構(gòu)體數(shù)組OS_Task,分配固定的內(nèi)存空間。
最后才是創(chuàng)建任務(wù)。
如果使用動態(tài)內(nèi)存分配,就可以省略前面步驟,直接創(chuàng)建任務(wù),在任務(wù)創(chuàng)建函數(shù)里通過動態(tài)內(nèi)存分配函數(shù),給任務(wù)動態(tài)開辟一塊內(nèi)存,如果對RTOS有研究,應(yīng)該知道我在講什么..
2.malloc使用場景2:探測器列表
項目3是需要和不同的探測器(遙控器、門磁探測器、紅外探測器、煙霧探測器等等)組網(wǎng)使用的。
我們做了一個菜單,在OLED屏上顯示已經(jīng)組網(wǎng)的探測器列表。
每個主機,已經(jīng)組網(wǎng)的探測器數(shù)量都不一樣,有些主機最多支持組網(wǎng)255個探測器。
每個探測器都有探測器ID、組網(wǎng)標志、序號、名稱等參數(shù)。
那是不是意味著,如果主機最大支持255個探測器,如果沒有動態(tài)內(nèi)存分配,就要提前定義能夠存儲255個探測器參數(shù)的結(jié)構(gòu)體數(shù)組?
事實上,我想到兩種方式。
第一種是先存到外部的flash里,用到了再讀出來,程序操作起來麻煩,而且效率慢,優(yōu)點是省RAM。
第二種是直接分配255個探測器的靜態(tài)存儲空間,程序操作爽,效率高,但費RAM,還好特么用了STM32。
我這個探測器列表菜單,用的是第二種方式,因為我主機對探測器數(shù)量的上限設(shè)置是20個,哈哈。
對于這種功能需求,王炸的解決方案,就是用動態(tài)內(nèi)存分配了!用時分配,用完釋放!
但是,不建議直接用malloc()?。?!
其實我第一次接觸內(nèi)存管理,是做藍牙產(chǎn)品,用TI協(xié)議棧的時候。
當(dāng)時有點奇怪的是,c語言標準庫有malloc()動態(tài)內(nèi)存分配和free()內(nèi)存釋放函數(shù),osal系統(tǒng)為什么要自己寫osal_mem_alloc()和osal_mem_free()?
直到后面自己做了一些復(fù)雜點的項目,自己也調(diào)過內(nèi)存管理代碼,才理解。
單片機上用malloc(),是個坑,有隱患。
我覺得內(nèi)存碎片,是萬惡之源。
malloc()函數(shù)本身只是動態(tài)分配內(nèi)存,并沒有直接解決內(nèi)存碎片問題。
什么是內(nèi)存碎片?
剛開始,我也不理解,什么是內(nèi)存碎片,網(wǎng)上搜了很多相關(guān)內(nèi)容,越繞越暈。
我嘗試用通俗易懂的語言,長話短說,能不能理解,看基礎(chǔ)和悟性了。
內(nèi)存碎片分為兩種:
1.外部碎片
想象一下,有一個大型的圖書館,圖書館的書架上擺滿了各種各樣的書籍,這些書籍大小可能不一樣,書籍就像內(nèi)存中的內(nèi)存塊(已被動態(tài)分配的內(nèi)存),書架上的空位代表空閑內(nèi)存(未被分配的內(nèi)存或者被釋放的內(nèi)存)。
當(dāng)讀者借閱書籍后,書架上會留下一些空位。隨著時間的推移,這些空位可能變得非常分散,就像散落在書架上的小塊空間。
如果突然要存放一本很大很厚的書,到書架上時,可能很難找到足夠大的連續(xù)空位來放置這本書。
那如果往后要存放的書,都是很大很厚的呢?
是不是雖然空位很多,但就是放不進去?那這塊空間是不是就浪費掉了?
在內(nèi)存分配時也是同理,如果頻繁地用malloc()分配很多零散的內(nèi)存塊,每個內(nèi)存塊占用的字節(jié)數(shù)都不一樣。
當(dāng)這些內(nèi)存塊使用完,被free()釋放以后,這塊空閑內(nèi)存,比如是8個字節(jié),那下次,再有動態(tài)分配內(nèi)存需求時,除非是8個字節(jié)或者以下才能使用這個內(nèi)存塊,如果是8個字節(jié)以上,這塊內(nèi)存塊就相當(dāng)于一直用不上,就浪費了。
所以說,即使總的空閑空間足夠,但由于碎片化,也不好滿足大內(nèi)存塊的分配請求。
這就是,在內(nèi)存管理中,外部內(nèi)存碎片化會導(dǎo)致系統(tǒng)無法為新的內(nèi)存請求,分配足夠的連續(xù)內(nèi)存空間,注意連續(xù)內(nèi)存空間很重要,如果不連續(xù),處理器就要不斷從整個內(nèi)存池去尋找,這樣讀取效率就會變低,這是內(nèi)存碎片的影響。
2.內(nèi)部碎片
內(nèi)部內(nèi)部碎片就是分配了內(nèi)存空間,但未被使用的部分。
為此,我做了一個實驗:
上圖程序里,我給p1和p2分配1個字節(jié)內(nèi)存,實際卻分配了8個字節(jié)的空間,在釋放前這7個字節(jié)都不能再被分配,相當(dāng)于7個字節(jié)空間就浪費了。
以上兩種碎片的產(chǎn)生,會讓程序產(chǎn)生一種很尷尬的現(xiàn)象,就是明明有很多空閑內(nèi)存,但總是分配失敗,甚至導(dǎo)致程序死機,而且這種死機現(xiàn)象,通常是沒有規(guī)律的。
印象中,我以前解決碎片問題的方法,大概是,內(nèi)存釋放后,把該內(nèi)存塊后面所有已分配的內(nèi)存塊往前遷移。
其實內(nèi)存管理,就是開辟一個很大的數(shù)組,稱內(nèi)存池。
然后后面所有的功能,比如動態(tài)內(nèi)存分配,內(nèi)存釋放,都是基于這個大數(shù)組去完成,會涉及到數(shù)據(jù)結(jié)構(gòu),涉及到算法。
所以,數(shù)據(jù)結(jié)構(gòu)和算法,這個時候針對性去學(xué)是最合適的。
很多人項目都沒做過,就去學(xué),沒什么鳥用,學(xué)完也不知道能干嘛。
說到這里,我相信你應(yīng)該沒有單片機上用malloc()的勇氣了吧?
小批量生產(chǎn)可能測不出來,大批量生產(chǎn)就會陸續(xù)出現(xiàn)死機現(xiàn)象了,碰到了,就偷偷躲廁所里哭吧,這種問題能找死個人!
至于很多人說的,比如單片機不用malloc(),是因為內(nèi)存資源有限,個人人為不是問題本質(zhì),一般能用上動態(tài)內(nèi)存分配的產(chǎn)品,單片機內(nèi)存資源都比較大。
本質(zhì)就是用malloc()容易產(chǎn)生內(nèi)存碎片,從而會引發(fā)一系列的問題,比如數(shù)據(jù)讀取效率問題、穩(wěn)定性問題等等...
PC上用malloc()估計也會存在內(nèi)存碎片的問題,只是電腦內(nèi)存動不動就上G,沒有嵌入式設(shè)備這么敏感,當(dāng)然PC可能還有別的方式去解決碎片化問題,這塊我沒做過,不做表態(tài)。
最后彩蛋時間,最近有粉絲問我怎么提升單片機編程思維和水平。
我做了開發(fā)10幾年,累計做過幾十個項目,我針對這些項目共性功能,比如任務(wù)創(chuàng)建、管理、隊列算法、LED特效、按鍵掃描等,寫了一個標準程序框架。
這個架構(gòu),我在2019年也錄了教程,我做新項目時,直接套用這個架構(gòu)去寫,效率直接起飛。
可以點擊下方??卡片看文章開頭領(lǐng)取。
《單片機入門到高級開掛學(xué)習(xí)路徑(附教程+工具)》文章來源:http://www.zghlxwxcb.cn/news/detail-837201.html
《單片機入門到高級開掛學(xué)習(xí)路徑(附教程+工具)》
《單片機入門到高級開掛學(xué)習(xí)路徑(附教程+工具)》
或者可以找「無際單片機」,全網(wǎng)同名的。文章來源地址http://www.zghlxwxcb.cn/news/detail-837201.html
到了這里,關(guān)于為什么單片機上的程序不建議使用malloc?的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!