0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

單片機(jī)上用malloc()是個(gè)坑,有隱患?

無(wú)際單片機(jī)編程 ? 來(lái)源:無(wú)際單片機(jī)編程 ? 2024-02-22 15:53 ? 次閱讀

單片機(jī)研發(fā)前幾年,一直沒(méi)用過(guò)動(dòng)態(tài)內(nèi)存分配的功能,但是如果想成為軟件架構(gòu)設(shè)計(jì)師,這是繞不過(guò)的一道坎。

其實(shí)單片機(jī)很少使用c標(biāo)準(zhǔn)庫(kù)自帶的malloc()函數(shù)去動(dòng)態(tài)分配內(nèi)存,除非,你看老板不爽...

因?yàn)橛腥毕?,文章后面?huì)提及。

一般是工程師借助現(xiàn)成的參考代碼,然后重新設(shè)計(jì)內(nèi)存管理代碼,改進(jìn)動(dòng)態(tài)內(nèi)存分配算法。

不過(guò)代碼難度挺大,c語(yǔ)言功底不好的,看到代碼會(huì)失聲痛哭....

不信?我裝個(gè)逼給你看!

下圖,是以前自己借鑒(抄襲),再吃透,后改進(jìn)的內(nèi)存管理代碼,測(cè)試已解決內(nèi)存碎片問(wèn)題。

43ddafca-d157-11ee-a297-92fbcf53809c.png

43f53000-d157-11ee-a297-92fbcf53809c.png

代碼沒(méi)多少,卻讓我充分感受到,編程語(yǔ)言只是工具,編程思維才是靈魂。

本來(lái)是計(jì)劃用在無(wú)際單片機(jī)特訓(xùn)營(yíng)項(xiàng)目6的,但是感覺(jué)太復(fù)雜了,怕老鐵們學(xué)著學(xué)著來(lái)罵我,所以這代碼就失寵了。

新手,或者有些一直從事比較簡(jiǎn)單產(chǎn)品工程師,可能無(wú)法理解,malloc的應(yīng)用場(chǎng)景,到底在哪里?

我以無(wú)際單片機(jī)特訓(xùn)營(yíng)項(xiàng)目3來(lái)舉例幾個(gè)使用場(chǎng)景,或許你就明白了。

1.malloc使用場(chǎng)景1:動(dòng)態(tài)任務(wù)創(chuàng)建

學(xué)過(guò)我們項(xiàng)目3的老鐵,不知道有沒(méi)有發(fā)現(xiàn)一個(gè)問(wèn)題。

在用我們那個(gè)"小系統(tǒng)"創(chuàng)建任務(wù)的時(shí)候,不夠靈活,每次增加新的任務(wù),要手動(dòng)在頭文件增加任務(wù)ID。

441628d2-d157-11ee-a297-92fbcf53809c.png

這樣做的目的,是為了給下面這個(gè)任務(wù)結(jié)構(gòu)體數(shù)組OS_Task,分配固定的內(nèi)存空間。

44257da0-d157-11ee-a297-92fbcf53809c.png

最后才是創(chuàng)建任務(wù)。

44347c74-d157-11ee-a297-92fbcf53809c.png

如果使用動(dòng)態(tài)內(nèi)存分配,就可以省略前面步驟,直接創(chuàng)建任務(wù),在任務(wù)創(chuàng)建函數(shù)里通過(guò)動(dòng)態(tài)內(nèi)存分配函數(shù),給任務(wù)動(dòng)態(tài)開(kāi)辟一塊內(nèi)存,如果對(duì)RTOS有研究,應(yīng)該知道我在講什么..

2.malloc使用場(chǎng)景2:探測(cè)器列表

項(xiàng)目3是需要和不同的探測(cè)器(遙控器、門磁探測(cè)器、紅外探測(cè)器、煙霧探測(cè)器等等)組網(wǎng)使用的。

我們做了一個(gè)菜單,在OLED屏上顯示已經(jīng)組網(wǎng)的探測(cè)器列表。

44428d14-d157-11ee-a297-92fbcf53809c.png

每個(gè)主機(jī),已經(jīng)組網(wǎng)的探測(cè)器數(shù)量都不一樣,有些主機(jī)最多支持組網(wǎng)255個(gè)探測(cè)器。

每個(gè)探測(cè)器都有探測(cè)器ID、組網(wǎng)標(biāo)志、序號(hào)、名稱等參數(shù)。

44562c48-d157-11ee-a297-92fbcf53809c.png

那是不是意味著,如果主機(jī)最大支持255個(gè)探測(cè)器,如果沒(méi)有動(dòng)態(tài)內(nèi)存分配,就要提前定義能夠存儲(chǔ)255個(gè)探測(cè)器參數(shù)的結(jié)構(gòu)體數(shù)組?

事實(shí)上,我想到兩種方式。

第一種是先存到外部的flash里,用到了再讀出來(lái),程序操作起來(lái)麻煩,而且效率慢,優(yōu)點(diǎn)是省RAM。

第二種是直接分配255個(gè)探測(cè)器的靜態(tài)存儲(chǔ)空間,程序操作爽,效率高,但費(fèi)RAM,還好特么用了STM32。

我這個(gè)探測(cè)器列表菜單,用的是第二種方式,因?yàn)槲抑鳈C(jī)對(duì)探測(cè)器數(shù)量的上限設(shè)置是20個(gè),哈哈。

446149b6-d157-11ee-a297-92fbcf53809c.png

對(duì)于這種功能需求,王炸的解決方案,就是用動(dòng)態(tài)內(nèi)存分配了!用時(shí)分配,用完釋放!

但是,不建議直接用malloc()?。?!

其實(shí)我第一次接觸內(nèi)存管理,是做藍(lán)牙產(chǎn)品,用TI協(xié)議棧的時(shí)候。

當(dāng)時(shí)有點(diǎn)奇怪的是,c語(yǔ)言標(biāo)準(zhǔn)庫(kù)有malloc()動(dòng)態(tài)內(nèi)存分配和free()內(nèi)存釋放函數(shù),osal系統(tǒng)為什么要自己寫osal_mem_alloc()和osal_mem_free()?

直到后面自己做了一些復(fù)雜點(diǎn)的項(xiàng)目,自己也調(diào)過(guò)內(nèi)存管理代碼,才理解。

單片機(jī)上用malloc(),是個(gè)坑,有隱患。

我覺(jué)得內(nèi)存碎片,是萬(wàn)惡之源。

malloc()函數(shù)本身只是動(dòng)態(tài)分配內(nèi)存,并沒(méi)有直接解決內(nèi)存碎片問(wèn)題。

什么是內(nèi)存碎片?

剛開(kāi)始,我也不理解,什么是內(nèi)存碎片,網(wǎng)上搜了很多相關(guān)內(nèi)容,越繞越暈。

我嘗試用通俗易懂的語(yǔ)言,長(zhǎng)話短說(shuō),能不能理解,看基礎(chǔ)和悟性了。

內(nèi)存碎片分為兩種:

1.外部碎片

想象一下,有一個(gè)大型的圖書館,圖書館的書架上擺滿了各種各樣的書籍,這些書籍大小可能不一樣,書籍就像內(nèi)存中的內(nèi)存塊(已被動(dòng)態(tài)分配的內(nèi)存),書架上的空位代表空閑內(nèi)存(未被分配的內(nèi)存或者被釋放的內(nèi)存)。

當(dāng)讀者借閱書籍后,書架上會(huì)留下一些空位。隨著時(shí)間的推移,這些空位可能變得非常分散,就像散落在書架上的小塊空間。

如果突然要存放一本很大很厚的書,到書架上時(shí),可能很難找到足夠大的連續(xù)空位來(lái)放置這本書。

那如果往后要存放的書,都是很大很厚的呢?

是不是雖然空位很多,但就是放不進(jìn)去?那這塊空間是不是就浪費(fèi)掉了?

在內(nèi)存分配時(shí)也是同理,如果頻繁地用malloc()分配很多零散的內(nèi)存塊,每個(gè)內(nèi)存塊占用的字節(jié)數(shù)都不一樣。

當(dāng)這些內(nèi)存塊使用完,被free()釋放以后,這塊空閑內(nèi)存,比如是8個(gè)字節(jié),那下次,再有動(dòng)態(tài)分配內(nèi)存需求時(shí),除非是8個(gè)字節(jié)或者以下才能使用這個(gè)內(nèi)存塊,如果是8個(gè)字節(jié)以上,這塊內(nèi)存塊就相當(dāng)于一直用不上,就浪費(fèi)了。

所以說(shuō),即使總的空閑空間足夠,但由于碎片化,也不好滿足大內(nèi)存塊的分配請(qǐng)求。

這就是,在內(nèi)存管理中,外部?jī)?nèi)存碎片化會(huì)導(dǎo)致系統(tǒng)無(wú)法為新的內(nèi)存請(qǐng)求,分配足夠的連續(xù)內(nèi)存空間,注意連續(xù)內(nèi)存空間很重要,如果不連續(xù),處理器就要不斷從整個(gè)內(nèi)存池去尋找,這樣讀取效率就會(huì)變低,這是內(nèi)存碎片的影響。

2.內(nèi)部碎片

內(nèi)部?jī)?nèi)部碎片就是分配了內(nèi)存空間,但未被使用的部分。

為此,我做了一個(gè)實(shí)驗(yàn):

446f9796-d157-11ee-a297-92fbcf53809c.png

上圖程序里,我給p1和p2分配1個(gè)字節(jié)內(nèi)存,實(shí)際卻分配了8個(gè)字節(jié)的空間,在釋放前這7個(gè)字節(jié)都不能再被分配,相當(dāng)于7個(gè)字節(jié)空間就浪費(fèi)了。

以上兩種碎片的產(chǎn)生,會(huì)讓程序產(chǎn)生一種很尷尬的現(xiàn)象,就是明明有很多空閑內(nèi)存,但總是分配失敗,甚至導(dǎo)致程序死機(jī),而且這種死機(jī)現(xiàn)象,通常是沒(méi)有規(guī)律的。

印象中,我以前解決碎片問(wèn)題的方法,大概是,內(nèi)存釋放后,把該內(nèi)存塊后面所有已分配的內(nèi)存塊往前遷移。

447a7bf2-d157-11ee-a297-92fbcf53809c.png

其實(shí)內(nèi)存管理,就是開(kāi)辟一個(gè)很大的數(shù)組,稱內(nèi)存池。

449fd1fe-d157-11ee-a297-92fbcf53809c.png

然后后面所有的功能,比如動(dòng)態(tài)內(nèi)存分配,內(nèi)存釋放,都是基于這個(gè)大數(shù)組去完成,會(huì)涉及到數(shù)據(jù)結(jié)構(gòu),涉及到算法。

所以,數(shù)據(jù)結(jié)構(gòu)和算法,這個(gè)時(shí)候針對(duì)性去學(xué)是最合適的。

很多人項(xiàng)目都沒(méi)做過(guò),就去學(xué),沒(méi)什么鳥用,學(xué)完也不知道能干嘛。

說(shuō)到這里,我相信你應(yīng)該沒(méi)有單片機(jī)上用malloc()的勇氣了吧?

小批量生產(chǎn)可能測(cè)不出來(lái),大批量生產(chǎn)就會(huì)陸續(xù)出現(xiàn)死機(jī)現(xiàn)象了,碰到了,就偷偷躲廁所里哭吧,這種問(wèn)題能找死個(gè)人!

至于很多人說(shuō)的,比如單片機(jī)不用malloc(),是因?yàn)閮?nèi)存資源有限,個(gè)人人為不是問(wèn)題本質(zhì),一般能用上動(dòng)態(tài)內(nèi)存分配的產(chǎn)品,單片機(jī)內(nèi)存資源都比較大。

本質(zhì)就是用malloc()容易產(chǎn)生內(nèi)存碎片,從而會(huì)引發(fā)一系列的問(wèn)題,比如數(shù)據(jù)讀取效率問(wèn)題、穩(wěn)定性問(wèn)題等等...

PC上用malloc()估計(jì)也會(huì)存在內(nèi)存碎片的問(wèn)題,只是電腦內(nèi)存動(dòng)不動(dòng)就上G,沒(méi)有嵌入式設(shè)備這么敏感,當(dāng)然PC可能還有別的方式去解決碎片化問(wèn)題,這塊我沒(méi)做過(guò),不做表態(tài)。





審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 單片機(jī)
    +關(guān)注

    關(guān)注

    6026

    文章

    44452

    瀏覽量

    630784
  • 探測(cè)器
    +關(guān)注

    關(guān)注

    14

    文章

    2590

    瀏覽量

    72795
  • C語(yǔ)言
    +關(guān)注

    關(guān)注

    180

    文章

    7581

    瀏覽量

    135541
  • OLED屏
    +關(guān)注

    關(guān)注

    0

    文章

    160

    瀏覽量

    20800
  • malloc
    +關(guān)注

    關(guān)注

    0

    文章

    52

    瀏覽量

    56

原文標(biāo)題:為什么單片機(jī)上的程序不建議使用malloc?

文章出處:【微信號(hào):nanshuqg,微信公眾號(hào):無(wú)際單片機(jī)編程】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    淺談 malloc 函數(shù)在單片機(jī)上的應(yīng)用

    聊聊 malloc函數(shù) 在單片機(jī)程序設(shè)計(jì)中怎么使用
    的頭像 發(fā)表于 05-18 09:35 ?2145次閱讀
    淺談 <b class='flag-5'>malloc</b> 函數(shù)在<b class='flag-5'>單片機(jī)上</b>的應(yīng)用

    為什么在單片機(jī)上的程序不怎么使用malloc,而PC上經(jīng)常使用?

    一樣跑在硬件上的,它們屬于一個(gè)層次的。過(guò)去之所以沒(méi)有區(qū)分出單片機(jī)上的程序和PC機(jī)上的程序的一些差異,就是沒(méi)有弄明白這一點(diǎn)。由此,以前的一些疑惑也就解開(kāi)了。為什么在單片機(jī)上的程序不怎么使
    發(fā)表于 05-03 13:33

    請(qǐng)問(wèn)TTL燒錄編程,單片機(jī)上要找哪五個(gè)

    TTL燒錄編程,單片機(jī)上要找哪五個(gè)
    發(fā)表于 01-24 20:27

    如何在單片機(jī)上也可正常使用動(dòng)態(tài)內(nèi)存分配

    51單片機(jī)內(nèi)存動(dòng)態(tài)分配序言最近玩51單片機(jī)碰到一個(gè)問(wèn)題,51中malloc函數(shù)并不能像在PC上一樣正常運(yùn)行,這涉及到了內(nèi)存池的概念。下面就來(lái)演示一下如何在
    發(fā)表于 11-19 07:36

    malloc的相關(guān)資料分享

    首先,malloc( )屬于標(biāo)準(zhǔn)C語(yǔ)言函數(shù),當(dāng)然可以在單片機(jī)上使用,如STM32可以先在啟動(dòng)文件中設(shè)置heap的大小,再使用動(dòng)態(tài)內(nèi)存分配: Heap_Size EQU 0x00000200 \\也就
    發(fā)表于 11-26 08:27

    如何在單片機(jī)上摁鍵編輯信息可以在單片機(jī)上顯示?

    做一個(gè)設(shè)計(jì)求指導(dǎo),就是想在單片機(jī)上摁鍵編輯信息可以在單片機(jī)上顯示,并且能發(fā)送到電腦上,還能收到電腦的的信息。
    發(fā)表于 09-28 06:37

    32單片機(jī)上的uCOSII和FreeRTOS兩個(gè)實(shí)時(shí)操作系統(tǒng)什么區(qū)別?

    32單片機(jī)上的uCOSII和FreeRTOS兩個(gè)實(shí)時(shí)操作系統(tǒng)什么區(qū)別啊,在上班之后一般是的哪一類實(shí)時(shí)操作系統(tǒng)比較多啊
    發(fā)表于 10-27 08:07

    Atmel AVR 單片機(jī)上網(wǎng)方案

    Atmel AVR 單片機(jī)上網(wǎng)方案
    發(fā)表于 01-14 15:04 ?6次下載

    淺談單片機(jī)上電復(fù)位后端口的狀態(tài)

    量避免處于輸出狀態(tài)(無(wú)論是輸出低還是輸出高) 為什么要這樣說(shuō)呢?因?yàn)?b class='flag-5'>單片機(jī)外圍電路的動(dòng)作就是靠單片機(jī)端口輸出低電平或者高電平來(lái)控制的。假如單片機(jī)端口一上電就處于輸出高或者低電平的狀態(tài),那么很容易出現(xiàn)誤動(dòng)作。例如,
    的頭像 發(fā)表于 11-30 18:17 ?3931次閱讀

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

    空間不足而分配失敗,從而導(dǎo)致系統(tǒng)崩潰,因此應(yīng)該慎用,或者自己實(shí)現(xiàn)內(nèi)存管理。 mem_malloc就是一個(gè)不會(huì)產(chǎn)生內(nèi)存碎片的、適合單片機(jī)使用的內(nèi)存管理模塊。
    的頭像 發(fā)表于 06-25 08:54 ?2941次閱讀
    分享可應(yīng)用于<b class='flag-5'>單片機(jī)</b>的內(nèi)存管理模塊mem_<b class='flag-5'>malloc</b>

    關(guān)于stm32 MCU申請(qǐng)動(dòng)態(tài)內(nèi)存malloc的認(rèn)識(shí)

    首先,malloc( )屬于標(biāo)準(zhǔn)C語(yǔ)言函數(shù),當(dāng)然可以在單片機(jī)上使用,如STM32可以先在啟動(dòng)文件中設(shè)置heap的大小,再使用動(dòng)態(tài)內(nèi)存分配: Heap_Size EQU 0x00000200 \\也就
    發(fā)表于 11-18 16:21 ?14次下載
    關(guān)于stm32 MCU申請(qǐng)動(dòng)態(tài)內(nèi)存<b class='flag-5'>malloc</b>的認(rèn)識(shí)

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

    項(xiàng)目場(chǎng)景:單片機(jī)使用malloc產(chǎn)生內(nèi)存泄露的問(wèn)題問(wèn)題描述:bug1:創(chuàng)建了一個(gè)結(jié)構(gòu)體指針,通過(guò)malloc動(dòng)態(tài)開(kāi)辟內(nèi)存的方式開(kāi)辟了一段內(nèi)存空間,然后進(jìn)行寫入數(shù)據(jù)修改數(shù)據(jù)的操作,但是下
    發(fā)表于 12-03 10:21 ?8次下載
    記錄<b class='flag-5'>單片機(jī)</b>使用<b class='flag-5'>malloc</b>產(chǎn)生內(nèi)存泄露的問(wèn)題及解決方法

    89系列單片機(jī)上機(jī)指導(dǎo)

    89系列單片機(jī)上機(jī)指導(dǎo)
    發(fā)表于 06-13 14:20 ?2次下載

    如何在單片機(jī)中使用malloc函數(shù)

    但是每個(gè)嵌入式 RTOS 都會(huì)有自己的內(nèi)存管理方式,本文就來(lái)聊聊我對(duì) malloc 函數(shù)在單片機(jī)程序設(shè)計(jì)中的一些看法。 本文并不是要說(shuō)明在單片機(jī)中怎么使用 malloc函數(shù),而是
    的頭像 發(fā)表于 04-24 09:50 ?2384次閱讀
    如何在<b class='flag-5'>單片機(jī)</b>中使用<b class='flag-5'>malloc</b>函數(shù)

    如何實(shí)現(xiàn)一個(gè)malloc

    任何一個(gè)用過(guò)或?qū)W過(guò)C的人對(duì)malloc都不會(huì)陌生。大家都知道malloc可以分配一段連續(xù)的內(nèi)存空間,并且在不再使用時(shí)可以通過(guò)free釋放掉。但是,許多程序員對(duì)malloc背后的事情并不
    的頭像 發(fā)表于 11-13 14:31 ?679次閱讀
    如何實(shí)現(xiàn)一<b class='flag-5'>個(gè)</b><b class='flag-5'>malloc</b>