當(dāng)前位置:首頁 > 公眾號精選 > 嵌入式軟件實戰(zhàn)派
[導(dǎo)讀]這次我成功將妹子約到了公司附近的咖啡館,繼續(xù)探討RTOS的heap的技術(shù)特點。當(dāng)我把準(zhǔn)備好的數(shù)據(jù)和動圖展示在她面前,她立馬激動起來了。

這次我成功將妹子約到了公司附近的咖啡館,繼續(xù)探討RTOS的heap的技術(shù)特點。當(dāng)我把準(zhǔn)備好的數(shù)據(jù)和動圖展示在她面前,她立馬激動起來了。仿佛我遞出來的是一束花、鉆戒,她驚訝不已,除了臉上少了幾分嬌羞……事情上這樣的,我得好好重頭講一講。1. 妹子的問題妹子好久沒有問我問題了,想著應(yīng)該是可以自己獨立干項目了吧。這也是好事,畢竟是我親自帶出來的徒弟。但我還是懷念她經(jīng)常問我問題的日子……
有一天傍晚快下班的時候,我問她,項目上的事自己能hold得住嗎?有問題隨時可以找我哦。
她想了想,欲言又止。
還沒等她說話,我接著說,是遇到什么問題了嗎?
“其實是這樣的,我是遇到了OS上的一些疑惑問題,但也不是很要緊??茨隳敲疵?,不好意思打擾你……”“哦……沒事啊,什么問題呢?”她說,自從上次我跟她分析了OS占用內(nèi)存的問題(見妹子告訴我她被欺負(fù)了)后,她就對OS的內(nèi)存分配有不少疑惑,很想將它搞個一清二楚。這不,她現(xiàn)在的問題是,FreeRTOS里的Heap1~Heap5有什么區(qū)別?
心想:額……這次完犢子了,我還真沒怎么研究過這幾個Heap的區(qū)別。但是我不能在她面前說不行啊。
突然,心生一計,若有其事淡定地跟她說,這是個好問題,得好好探討下。然后我順手拿出手機看了看時間,問她,明天晚上有空么?
“有。”她回答很干脆。
這次,我得換個方式跟她講解這個Heap,不能像以前那樣了……
2. 熬夜研究heap于是,我背了筆記本回家,開始鉆研這個heap的用法,得用豐富的知識和強有力的技能征服妹子。
首先,我將這幾個heap的c文件移植到PC運行環(huán)境,用自動化手段分析其使用情況。我寫了個main.c文件,分別與heap_1.c~heap_5.c進行編譯。
主要思路是,向heap申請并釋放內(nèi)存,看看其地址占用空間,就一目了然了。
 addr1 = alloc_x(1); addr2 = alloc_x(2); addr4 = alloc_x(4); addr8 = alloc_x(8); addr16 = alloc_x(16); addr32 = alloc_x(32);  free_x(addr1); addr1 = alloc_x(1); free_x(addr4); addr2 = alloc_x(2); free_x(addr8); addr4 = alloc_x(4); addr4 = alloc_x(4); free_x(addr16); addr1 = alloc_x(1); addr2 = alloc_x(2); addr4 = alloc_x(4); addr8 = alloc_x(8); addr16 = alloc_x(16); addr1 = alloc_x(1); free_x(addr2); free_x(addr4); free_x(addr8); free_x(addr16); addr6 = alloc_x(6); addr10 = alloc_x(10);
這里面的alloc_xfree_x分別調(diào)用了pvPortMallocvPortFree,并打印一些信息。
void* alloc_x(size_t size){ void* addr = pvPortMalloc(size); size_t res = xPortGetFreeHeapSize(); printf("Alloc : addr=0x%p, size:0x%02X, remain:0x%04X\r\n", addr, size, res); return addr;} void free_x(void* addr){ vPortFree( addr); size_t res = xPortGetFreeHeapSize(); printf("Free  : addr=0x%p, remain:0x%04X\r\n", addr, res);}
總以為很順利,誰知道,這heap依賴的頭文件一層套一層……一狠心,大刀闊斧屏蔽了頭文件里面的內(nèi)容,手動添加heap需要的依賴項。
好不容易,編譯通過了,在搞heap_1.c這個的時候,在運行到vPortFree,就掛了!查了下代碼,發(fā)現(xiàn)heap_1原來是不允許free內(nèi)存的。
void vPortFree( void * pv ){ /* Memory cannot be freed using this scheme.  See heap_2.c, heap_3.c and * heap_4.c for alternative implementations, and the memory management pages of * https://www.FreeRTOS.org for more information. */ ( void ) pv;  /* Force an assert as it is invalid to call this function. */ configASSERT( pv == NULL );}
因為它只實現(xiàn)了pvPortMalloc而沒實現(xiàn)vPortFree,所以這個vPortFree是沒用的,僅僅是個兼容性接口而已。
接著,把后面的heap_2~heap_5的編譯運行問題一個個搞定了。
Note:我把整個工程打包好了,關(guān)注公眾號“嵌入式軟件實戰(zhàn)派”,在后臺回復(fù)“heap”即可獲得下載鏈接。
通過輸出的log信息,我還細(xì)心地做了個內(nèi)存分配動圖。
搞完這一波,看了下時間,竟然是晚上12點了。
然后,我居然興奮得睡不著,想著怎么跟她講解這個技術(shù)問題。
第二天,突發(fā)奇想,約她在公司附近的咖啡館!她居然爽快地答應(yīng)了??!
3. 促膝長談晚上下班,我們一起到了咖啡廳,就像一對小……伙伴程序員,背著筆記本電腦。跟異性來這種地方,我還有些不好意思。
為了避免尷尬,單刀直入,打開筆記本,把準(zhǔn)備好的材料跟她一一講解。
“師兄,我們不點個咖啡嗎?”
“呵呵呵……其實……你喜歡和什么?”
……

她說晚上不喝咖啡,于是我給她點了一杯奶茶,然后迫不及待地跟她將這個heap的情況。

一開始,我用官方的文檔解釋給她說明了下總體的情況:

我問她,“你知道FreeRTOS為什么不用C庫中的malloc()free()函數(shù)來分配和釋放內(nèi)存嗎?”

“因為,不安全?!?

我聽她這么肯定的說,想著她肯定是對RTOS有很深入的認(rèn)識的。

是的,C庫中的malloc()free()函數(shù):

1. they are not always available on embedded systems,

2. they take up valuable code space,

3. they are not thread safe, and

4. they are not deterministic (the amount of time taken to execute the function will differ from call to call)

FreeRTOS
“所以,F(xiàn)reeRTOS的幾個heap是為了解決這幾個問題的。”
她點了點頭,然后低頭喝了一口奶茶。我看她那手捧奶茶的溫柔,恰好點綴了窗外的夕陽……多想多停留在這一刻,但我怕她看到我在看她,接著說:“那么,這幾個heap有什么區(qū)別呢?總的來說是這樣的?!?br />

heap_1 - 最簡單的實現(xiàn)形式,不支持Free內(nèi)存;

heap_2 - 允許內(nèi)存Free,但不會合并free的內(nèi)存塊;

heap_3 - 是malloc() 和free() 的抽象層,多加了線程安全措施;

heap_4 - 合并free的塊,避免碎片

heap_5 - 類似heap_4,增加了塊內(nèi)存段操作。

“嗯!”她輕聲說。其實她已經(jīng)看過了這些解釋了,但是不是很理解,她想深入一點的,深入一點的學(xué)習(xí)。“‘Talk is cheap’,那么,我們直接上代碼吧。”
她呵呵大笑。笑的樣子也特別可愛。
“我們就按照官方的解釋,來驗證下。我寫了段測試代碼,你看看這段log就知道了?!?br />
Base Addr: 0x407080Alloc : addr=0x00407080, size:0x01, remain:0x27F0Alloc : addr=0x00407088, size:0x02, remain:0x27E8Alloc : addr=0x00407090, size:0x04, remain:0x27E0Alloc : addr=0x00407098, size:0x08, remain:0x27D8Alloc : addr=0x004070A0, size:0x10, remain:0x27C8Alloc : addr=0x004070B0, size:0x20, remain:0x27A8Free : addr=0x00407080, remain:0x27A8Alloc : addr=0x004070D0, size:0x01, remain:0x27A0Free : addr=0x00407090, remain:0x27A0Alloc : addr=0x004070D8, size:0x02, remain:0x2798Free : addr=0x00407098, remain:0x2798Alloc : addr=0x004070E0, size:0x04, remain:0x2790Alloc : addr=0x004070E8, size:0x04, remain:0x2788Free : addr=0x004070A0, remain:0x2788Alloc : addr=0x004070F0, size:0x01, remain:0x2780Alloc : addr=0x004070F8, size:0x02, remain:0x2778Alloc : addr=0x00407100, size:0x04, remain:0x2770Alloc : addr=0x00407108, size:0x08, remain:0x2768Alloc : addr=0x00407110, size:0x10, remain:0x2758Alloc : addr=0x00407120, size:0x01, remain:0x2750Free : addr=0x004070F8, remain:0x2750Free : addr=0x00407100, remain:0x2750Free : addr=0x00407108, remain:0x2750Free : addr=0x00407110, remain:0x2750Alloc : addr=0x00407128, size:0x06, remain:0x2748Alloc : addr=0x00407130, size:0x0A, remain:0x2738
她準(zhǔn)備站起來,把頭湊過來看,我把筆記本轉(zhuǎn)過去給她。然后我繼續(xù)解釋說,“這個Free是沒有意義的”。
“哦?”她似乎有些不相信,然后試圖口算這些地址值。
“我再給個圖你看看?!?br />

“哇哦……這顏色是什么意思,代表申請的內(nèi)存塊嗎?怎么還有這么多空隙的?”她低聲問道,似乎有點好奇,又有點不是很相信的樣子。
“是的,要顏色的地方是表示內(nèi)存申請占有的地方,至于空隙嘛,我一會再跟你解釋下?!蔽医又f,“歪著頭怎么看呢!要不坐過來我這邊,我還有一個動圖?!?br />

“厲害!這都可以做出來,走心了……”
“你仔細(xì)看,其實這個vPortFree執(zhí)行的地方,內(nèi)存是沒有變化的?!?br /> “真的哦,heap_1是不能釋放內(nèi)存的?!蓖蝗唬矣X得我很有成就感。
“那么,為什么會有這么多空隙的呢?我們看看這段代碼就清楚了。”
void * pvPortMalloc( size_t xWantedSize ){ void * pvReturn = NULL; static uint8_t * pucAlignedHeap = NULL;  /* Ensure that blocks are always aligned. */ #if ( portBYTE_ALIGNMENT != 1 ) { if( xWantedSize & portBYTE_ALIGNMENT_MASK ) { /* Byte alignment required. Check for overflow. */ if ( (xWantedSize + ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) )) > xWantedSize ) { xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ); } else { xWantedSize = 0; } } } #endif
“哦……原來最大多占了一個portBYTE_ALIGNMENT的空間?!彼嗽斄艘魂囘@個代碼說。
“所以,官方有說,自從有了static的內(nèi)存分配方法,就很少用這個heap_1了?!?br /> “嗯!”她似乎很滿足的樣子,伸手把奶茶拿過來,接著喝了一口。
我也喝了一口咖啡,突然覺得這個咖啡不苦了。她起身,準(zhǔn)備要坐回去。
“等下,我這還有其他數(shù)據(jù),給你看看heap_2的情況?!蔽艺f后,她慢慢坐了下來。夕陽已慢慢落在了城市的高樓之中,道路上依然車水馬龍,而安靜的咖啡館有種說不出來的溫馨。
“那么heap_2有什么不一樣呢?我們直接看圖吧?!?br />

“咦?怎么有更多的孔隙了?”
“是啊,我也納悶,但看了下源碼,確實會這樣,其中有一段是這樣的。”
 /* The wanted size must be increased so it can contain a BlockLink_t * structure in addition to the requested amount of bytes. */ if( ( xWantedSize > 0 ) && ( ( xWantedSize + heapSTRUCT_SIZE ) >  xWantedSize ) ) /* Overflow check */ { xWantedSize += heapSTRUCT_SIZE;  /* Byte alignment required. Check for overflow. */ if( ( xWantedSize + ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ) ) > xWantedSize ) { xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ); configASSERT( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) == 0 ); } else { xWantedSize = 0; } }
我接著解釋說,“你看,用heap_2每次申請一段內(nèi)存,都要多占一段heapSTRUCT_SIZE和一段portBYTE_ALIGNMENT 空間?!?br /> “哦,怪不得,我們項目定義了32K的RAM都差不多用完了,我算了下實際的分配,還差很遠(yuǎn),原來問題在這呢!”她似乎有種茅舍頓開的感覺。
“那么heap_3又是怎樣的呢?”她主動問我要圖片來看了。

“我用PC上位機軟件模擬的,heap_3用的是標(biāo)準(zhǔn)庫的malloc()和free(),似乎沒啥規(guī)律,其實沒什么參考價值的。”
“好吧……那heap_4呢?”她似乎有點失落的樣子,而又“肆無忌憚”起來,直問我要圖看。
我不慌不忙打開了這個圖。

“好像跟heap_2一樣的哦……”
“是的,很像。但是,有個很重要的區(qū)別,你看這最后一幀內(nèi)容,特別是最后紫色的這塊。”我特意將heap_2的和heap_4的拿出來對比了下。

“看起來似乎heap_4更省空間……哈哈!”看著這兩個圖的對比,她樂了起來,像個天真的孩子。
“雖然還是很多孔隙,但是free掉的空間是可以合并的,這個heap_4的好處就在這了。”
“是的,師兄你真厲害!”
“哈哈!”
“對了,還有heap_5的呢?”

“哦?跟heap_4的沒啥區(qū)別哦……”這說話拉長的語調(diào),越來越可愛了。

“效果看起來,確實是一樣的,但是heap_5是可以跨不連續(xù)區(qū)域的。官方文檔也是這么說的?!?

This scheme uses the same first fit and memory coalescence algorithms as heap_4, and allows the heap to span multiple non adjacent (non-contiguous) memory regions.

FreeRTOS
“那么,它是怎么跨區(qū)域的呢?”她突然好奇起來。
“給你看段代碼吧。其實它多了一個函數(shù)。”
void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions )
“這個const HeapRegion_t * const pxHeapRegions就是定義不同區(qū)域段的。”
“怎么分段的呢?”“那,我們看這個官方的例子。”
// HeapRegion_t xHeapRegions[] =// {//     { ( uint8_t * ) 0x80000000UL, 0x10000 }, << Defines a block of 0x10000 bytes starting at address 0x80000000//     { ( uint8_t * ) 0x90000000UL, 0xa0000 }, << Defines a block of 0xa0000 bytes starting at address of 0x90000000//     { NULL, 0 }                << Terminates the array.// };// vPortDefineHeapRegions( xHeapRegions ); << Pass the array into vPortDefineHeapRegions().


本站聲明: 本文章由作者或相關(guān)機構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫毥谦F公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運行,同時企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險,如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機 衛(wèi)星通信

要點: 有效應(yīng)對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅持高質(zhì)量發(fā)展策略,塑強核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運營商 數(shù)字經(jīng)濟

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術(shù)學(xué)會聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(shù)(集團)股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉