色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

不直接使用C標準庫中的內存管理函數的原因

RTThread物聯網操作系統 ? 來源:lp ? 2019-04-05 15:37 ? 次閱讀

前言

本文講RT-Thread的內存管理,包括為何不使用C標準庫的內存管理函數、內存管理的特點、RT-Thread 程序內存分布、內存堆管理、內存池管理以及使用STM32進行實驗。

一、不直接使用 C 標準庫中的內存管理函數的原因

很多人會有疑問,為什么不直接使用 C 標準庫中的內存管理函數呢?在電腦中我們可以用malloc()和 free()這兩個函數動態的分配內存和釋放內存。但是,在嵌入式實時操作系統中,調用 malloc()和 free()卻是危險的,原因有以下幾點:

1、這些函數在小型嵌入式系統中并不總是可用的,小型嵌入式設備中的 RAM 不足。

2、它們的實現可能非常的大,占據了相當大的一塊代碼空間。

3、他們幾乎都不是線程安全的。

4、它們并不是確定的,每次調用這些函數執行的時間可能都不一樣。

5、它們有可能產生碎片。

6、這兩個函數會使得鏈接器配置得復雜。

7、如果允許堆空間的生長方向覆蓋其他變量占據的內存,它們會成為 debug 的災難 。

二、內存管理的功能特點

1、分配內存的時間必須是確定的。一般內存管理算法是根據需要存儲的數據的長度在內存中去尋找一個與這段數據相適應的空閑內存塊,然后將數據存儲在里面。而尋找這樣一個空閑內存塊所耗費的時間是不確定的,因此對于實時系統來說,這就是不可接受的,實時系統必須要保證內存塊的分配過程在可預測的確定時間內完成,否則實時任務對外部事件的響應也將變得不可確定。

2、隨著內存不斷被分配和釋放,整個內存區域會產生越來越多的碎片(因為在使用過程中,申請了一些內存,其中一些釋放了,導致內存空間中存在一些小的內存塊,它們地址不連續,不能夠作為一整塊的大內存分配出去),系統中還有足夠的空閑內存,但因為它們地址并非連續,不能組成一塊連續的完整內存塊,會使得程序不能申請到大的內存。對于通用系統而言,這種不恰當的內存分配算法可以通過重新啟動系統來解決 (每個月或者數個月進行一次),但是對于那些需要常年不間斷地工作于野外的嵌入式系統來說,就變得讓人無法接受了。

3、嵌入式系統的資源環境也是不盡相同,有些系統的資源比較緊張,只有數十 KB 的內存可供分配,而有些系統則存在數 MB 的內存,如何為這些不同的系統,選擇適合它們的高效率的內存分配算法,就將變得復雜化。

三、RT-Thread 程序內存分布

一般 MCU 包含的存儲空間有:片內 Flash 與片內 RAM,RAM 相當于內存,Flash 相當于硬盤。

1、對于STM32,在keil編譯后,會出現如下信息

上面提到的 Program Size 包含以下幾個部分:

(1)Code:代碼段,存放程序的代碼部分;

(2)RO-data:只讀數據段,存放程序中定義的常量;

(3)RW-data:讀寫數據段,存放初始化為非 0 值的全局變量;

(4)ZI-data:0 數據段,存放未初始化的全局變量及初始化為 0 的變量;

編譯完工程會生成一個. map 的文件,該文件說明了各個函數占用的尺寸和地址,在文件的最后幾行也說明了上面幾個字段的關系:

1TotalROSize(Code+ROData)43688(42.66kB)2TotalRWSize(RWData+ZIData)3976(3.88kB)3TotalROMSize(Code+ROData+RWData)43812(42.79kB)4

2、程序運行之前,需要有文件實體被燒錄到 STM32 的 Flash 中,一般是 bin 或者 hex 文件,該被燒錄文件稱為可執行映像文件。如圖下圖 中左圖所示,是可執行映像文件燒錄到 STM32 后的內存分布,它包含 RO 段和 RW 段兩個部分:其中 RO 段中保存了 Code、RO-data 的數據,RW 段保存了 RW-data 的數據,由于 ZI-data 都是 0,所以未包含在映像文件中。

RT-Thread 內存分布(來源RT-Thread編程指南)

3、STM32 在上電啟動之后默認從 Flash 啟動,啟動之后會將 RW 段中的 RW-data(初始化的全局變量)搬運到 RAM 中,但不會搬運 RO 段,即 CPU 的執行代碼從 Flash 中讀取,另外根據編譯器給出的 ZI 地址和大小分配出 ZI 段,并將這塊 RAM 區域清零。

四、內存堆管理

內存堆管理根據具體內存設備劃分為三種情況:(1)針對小內存塊的分配管理(小內存管理算法);(2)針對大內存塊的分配管理(slab 管理算法);(3)針對多內存堆的分配情況(memheap 管理算法)

1、將 *“ZI 段結尾處”* 到內存尾部的空間用作內存堆

(1)內存堆管理用于管理一段連續的內存空間如下圖所示,RT-Thread 將 “ZI 段結尾處” 到內存尾部的空間用作內存堆。

RT-Thread 內存分布(來源RT-Thread編程指南)

(2)在前面的其他筆記,都是從內部SRAM申請一塊靜態內存來作為內存使用。

1#ifdefined(RT_USING_USER_MAIN)&&defined(RT_USING_HEAP) 2#defineRT_HEAP_SIZE6*1024 3/*從內部SRAM申請一塊靜態內存來作為內存堆使用*/ 4staticuint32_trt_heap[RT_HEAP_SIZE];//heapdefaultsize:24K(1024*4*6) 5 6RT_WEAKvoid*rt_heap_begin_get(void) 7{ 8returnrt_heap; 9}1011RT_WEAKvoid*rt_heap_end_get(void)12{13returnrt_heap+RT_HEAP_SIZE;14}15#endif161718/*在rt_hw_board_init中*/1920rt_system_heap_init(rt_heap_begin_get(),rt_heap_end_get());

(3)那么接下來,我們修改代碼,將 “ZI 段結尾處” 到內存尾部的空間用作內存堆。

(A)在board.h添加如下代碼:

1#ifdef__ICCARM__ 2//Use*.icframsymbal,toavoidhardcode. 3externchar__ICFEDIT_region_IRAM1_end__; 4#defineSTM32_SRAM_END&__ICFEDIT_region_IRAM1_end__ 5#else 6#defineSTM32_SRAM_SIZE96/*根據自己的MCU不同修改*/ 7#defineSTM32_SRAM_END(0x20000000+STM32_SRAM_SIZE*1024)/*根據自己的MCU不同修改*/ 8#endif 910#ifdef__CC_ARM11externintImage$$RW_IRAM1$$ZI$$Limit;12#defineHEAP_BEGIN(&Image$$RW_IRAM1$$ZI$$Limit)13#elif__ICCARM__14#pragmasection="HEAP"15#defineHEAP_BEGIN(__segment_end("HEAP"))16#else17externint__bss_end;18#defineHEAP_BEGIN(&__bss_end)19#endif2021#defineHEAP_ENDSTM32_SRAM_END

(B)在board.c中將前面第(2)的那部分代碼全部去掉,然后修改rt_hw_board_init函數,在后面加入如下代碼:

1#ifdefined(RT_USING_USER_MAIN)&&defined(RT_USING_HEAP)2rt_system_heap_init((void*)HEAP_BEGIN,(void*)HEAP_END);3#endif

2、小內存管理算法

(1)小內存管理算法是一個簡單的內存分配算法。初始時,它是一塊大的內存,其大小為(MEM_SIZE)。

初始時的內存(來源[野火?]《RT-Thread 內核實現與應用開發實戰—基于STM32》)

(2)當需要分配內存塊時,將從這個大的內存塊上分割出相匹配的內存塊,然后把分割出來的空閑內存塊還回給堆管理系統中。每個內存塊都包含一個管理用的數據頭,通過這個頭把使用塊與空閑塊用雙向鏈表的方式鏈接起來(內存塊鏈表)。

小內存管理工作機制圖(來源[野火?]《RT-Thread 內核實現與應用開發實戰—基于STM32》)

(3)每個內存塊(不管是已分配的內存塊還是空閑的內存塊)都包含一個數據頭,其中包括:

(A)magic:變數(或稱為幻數),它會被初始化成 0x1ea0(即英文單詞 heap),用于標記這個內存塊是一個內存管理用的內存數據塊;變數不僅僅用于標識這個數據塊是一個內存管理用的內存數據塊,實質也是一個內存保護字:如果這個區域被改寫,那么也就意味著這塊內存塊被非法改寫(正常情況下只有內存管理器才會去碰這塊內存)。

(B)used:指示出當前內存塊是否已經分配。

(4)內存管理的在表現主要體現在內存的分配與釋放上,小型內存管理算法可以用以下例子體現出來??臻e鏈表指針 lfree 初始指向 32 字節的內存塊。當用戶線程要再分配一個 64 字節的內存塊時,但此 lfree 指針指向的內存塊只有 32 字節并不能滿足要求,內存管理器會繼續尋找下一內存塊,當找到再下一塊內存塊,128 字節時,它滿足分配的要求。因為這個內存塊比較大,分配器將把此內存塊進行拆分,余下的內存塊(52字節)繼續留在 lfree鏈表中,在每次分配內存塊前,都會留出 12 字節數據頭用于 magic,used 信息及鏈表節點使用。返回給應用的地址實際上是這塊內存塊 12 字節以后的地址,而數據頭部分是用戶永遠不應該改變的部分。

小內存管理算法鏈表結構示意圖(來源[野火?]《RT-Thread 內核實現與應用開發實戰—基于STM32》)

分配 64 字節后的鏈表結構(來源[野火?]《RT-Thread 內核實現與應用開發實戰—基于STM32》)

(5)釋放時則是相反的過程,分配器會查看前后相鄰的內存塊是否空閑,如果空閑則合并成一個大的空閑內存塊。

3、slab 管理算法

RT-Thread 的 slab 分配器是在 DragonFly BSD 創始人 Matthew Dillon 實現的 slab 分配器基礎上,針對嵌入式系統優化的內存分配算法。最原始的 slab 算法是 Jeff Bonwick 為 Solaris 操作系統而引入的一種高效內核內存分配算法。RT-Thread 的 slab 分配器實現主要是去掉了其中的對象構造及析構過程,只保留了純粹的緩沖型的內存池算法。slab 分配器會根據對象的大小分成多個區(zone),也可以看成每類對象有一個內存池,如下圖所示:

slab 內存分配結構圖(來源RT-Thread編程指南)

一個 zone 的大小在 32K 到 128K 字節之間,分配器會在堆初始化時根據堆的大小自動調整。系統中的 zone 最多包括 72 種對象,一次最大能夠分配 16K 的內存空間,如果超出了 16K 那么直接從頁分配器中分配。每個 zone 上分配的內存塊大小是固定的,能夠分配相同大小內存塊的 zone 會鏈接在一個鏈表中,而 72 種對象的 zone 鏈表則放在一個數組(zone_array[])中統一管理。

下面是內存分配器主要的兩種操作:

(1)內存分配:假設分配一個 32 字節的內存,slab 內存分配器會先按照 32 字節的值,從 zone array 鏈表表頭數組中找到相應的 zone 鏈表。如果這個鏈表是空的,則向頁分配器分配一個新的 zone,然后從 zone 中返回第一個空閑內存塊。如果鏈表非空,則這個 zone 鏈表中的第一個 zone 節點必然有空閑塊存在(否則它就不應該放在這個鏈表中),那么就取相應的空閑塊。如果分配完成后,zone 中所有空閑內存塊都使用完畢,那么分配器需要把這個 zone 節點從鏈表中刪除。

(2)內存釋放:分配器需要找到內存塊所在的 zone 節點,然后把內存塊鏈接到 zone 的空閑內存塊鏈表中。如果此時zone 的空閑鏈表指示出 zone 的所有內存塊都已經釋放,即 zone 是完全空閑的,那么當 zone 鏈表中全空閑 zone 達到一定數目后,系統就會把這個全空閑的 zone 釋放到頁面分配器中去。

4、memheap 管理算法

(1)memheap 管理算法適用于系統含有多個地址可不連續的內存堆。使用 memheap 內存管理可以簡化系統存在多個內存堆時的使用:當系統中存在多個內存堆的時候,用戶只需要在系統初始化時將多個所需的memheap 初始化,并開啟 memheap 功能就可以很方便地把多個 memheap(地址可不連續)粘合起來用于系統的 heap 分配。

注意:在開啟 memheap 之后原來的 heap 功能將被關閉,兩者只可以通過打開或關閉RT_USING_MEMHEAP_AS_HEAP來選擇其一。

(2)memheap 工作機制如下圖所示,首先將多塊內存加入memheap_item鏈表進行粘合。當分配內存塊時,會先從默認內存堆去分配內存,當分配不到時會查找 memheap_item 鏈表,嘗試從其他的內存堆上分配內存塊。應用程序不用關心當前分配的內存塊位于哪個內存堆上,就像是在操作一個內存堆。

memheap 處理多內存堆(來源RT-Thread編程指南)

(3)對于有部分ST MCU是將內部SRAM分為地址不連續的兩部分SRAM1和SRAM2,那么就可以用memheap管理算法,例如IoT board的MCU STM32L475VET6。在前面講將到的 “ZI 段結尾處” 到內存尾部的空間用作內存堆,只是修改了SRAM1(96K)部分,那么如果想用SRAM2(32K)部分,需要修改代碼。

(A)在board.h中加入如下代碼:

1/*根據自己的MCU不同,確認MCU內部SRAM是否有分為兩塊SRAM1和SRAM2,STM32L475VET6內部SRAM分為SRAM1和SRAM2兩塊地址不連續*/2#defineSTM32_SRAM2_SIZE323#defineSTM32_SRAM2_BEGIN(0x10000000u)4#defineSTM32_SRAM2_END(0x10000000+STM32_SRAM2_SIZE*1024)5#defineSTM32_SRAM2_HEAP_SIZE((uint32_t)STM32_SRAM2_END-(uint32_t)STM32_SRAM2_BEGIN)

(B)在board.c中加入如下代碼:

1#ifdefined(RT_USING_MEMHEAP)&&defined(RT_USING_MEMHEAP_AS_HEAP)2staticstructrt_memheapsystem_heap;3#endif

(C)修改board.c中的rt_hw_board_init函數,內存堆配置和初始化代碼改為:

1#ifdefined(RT_USING_MEMHEAP)&&defined(RT_USING_MEMHEAP_AS_HEAP)2rt_system_heap_init((void*)HEAP_BEGIN,(void*)HEAP_END);3rt_memheap_init(&system_heap,"sram2",(void*)STM32_SRAM2_BEGIN,STM32_SRAM2_HEAP_SIZE);4#else5rt_system_heap_init((void*)HEAP_BEGIN,(void*)HEAP_END);6#endif

(4)根據自己是否想用使用SRAM2來決定是否使用memheap 管理算法,在rtconfig.h打開關閉相關宏來實現,如需要使用memheap 管理算法,打開如下宏:

1#defineRT_USING_MEMHEAP//定義該宏可開啟兩個或以上內存堆拼接的使用,未定義則關閉2#defineRT_USING_MEMHEAP_AS_HEAP

(5)如果RT_USING_MEMHEAP和RT_USING_MEMHEAP_AS_HEAP這兩個宏打開了,則使用memheap,那么系統內存堆的時候首先會從SRAM1(96K的那塊)分配內存,當SRAM1(96K的那塊)用完了再到SRAM2(32K那塊)分配。

(6)打開RT_USING_MEMHEAP_AS_HEAP之后,實現的算法不同,比如rt_malloc()函數的實現。

5、內存堆配置和初始化

(1)在使用內存堆時,必須要在系統初始化的時候進行堆的初始化,可以通過下面的函數接口完成:

1voidrt_system_heap_init(void*begin_addr,void*end_addr);

(A)入口參數

begin_addr:堆內存區域起始地址。end_addr:堆內存區域結束地址。

(2)在使用 memheap 堆內存時,必須要在系統初始化的時候進行堆內存的初始化,可以通過下面的函數接口完成:

1rt_err_trt_memheap_init(structrt_memheap*memheap,2constchar*name,3void*start_addr,4rt_uint32_tsize);

(A)入口參數:

memheap:memheap 控制塊。name:內存堆的名稱。start_addr:堆內存區域起始地址。size:堆內存大小。

(B)返回值:

RT_EOK:成功。

6、內存堆的管理方式

(1)申請內存塊:會從系統堆空間中找到合適大小的內存塊,然后把內存塊可用地址返回給用戶,函數接口如下:

1void*rt_malloc(rt_size_tsize);

(A)入口參數:

size:需要分配的內存塊的大小,單位為字節。

(B)返回值:

分配的內存塊地址:成功。RT_NULL:失敗。

(2)釋放內存塊:應用程序使用完從內存分配器中申請的內存后,必須及時釋放,否則會造成內存泄漏,會把待釋放的內存還回給堆管理器中,函數接口如下:

1voidrt_free(void*rmem);

(A)入口參數:

rmem:待釋放的內存塊指針。

(3)重分配內存塊:在已分配內存塊的基礎上重新分配內存塊的大?。ㄔ黾踊蚩s小),在進行重新分配內存塊時,原來的內存塊數據保持不變(縮小的情況下,后面的數據被自動截斷),函數接口如下:

1void*rt_realloc(void*rmem,rt_size_tnewsize);

(A)入口參數:

rmem:指向已分配的內存塊。newsize:重新分配的內存大小。

(B)返回值:

重新分配的內存塊地址:成功。RT_NULL:失敗。

(4)分配多內存塊:從內存堆中分配連續內存地址的多個內存塊,可以通過下面的函數接口完成:

1void*rt_calloc(rt_size_tcount,rt_size_tsize);

(A)入口參數:

count:內存塊數量。size:內存塊容量。

(B)返回值:

指向第一個內存塊地址的指針:成功,并且所有分配的內存塊都被初始化成零。RT_NULL:分配失敗。

(5)設置分配內存鉤子函數:在分配內存塊過程中,用戶可設置一個鉤子函數,設置的鉤子函數會在內存分配完成后進行回調。回調時,會把分配到的內存塊地址和大小做為入口參數傳遞進去,函數接口如下:

1voidrt_malloc_sethook(void(*hook)(void*ptr,rt_size_tsize));

(A)hook:鉤子函數指針。

(B)void hook(void *ptr, rt_size_t size); 函數接口參數:

ptr:分配到的內存塊指針。 size:分配到的內存塊的大小。

(6)設置是否內存鉤子函數:在釋放內存時,用戶可設置一個鉤子函數,設置的鉤子函數會在調用內存釋放完成前進行回調?;卣{時,釋放的內存塊地址會做為入口參數傳遞進去(此時內存塊并沒有被釋放),函數接口如下:

1voidrt_free_sethook(void(*hook)(void*ptr));

(A)hook:鉤子函數指針。

(B)void hook(void *ptr); 函數接口參數:

ptr:待釋放的內存塊指針。

五、內存池

內存堆管理器可以分配任意大小的內存塊,非常靈活和方便。但其也存在明顯的缺點:一是分配效率不高,在每次分配時,都要空閑內存塊查找;二是容易產生內存碎片。為了提高內存分配的效率,并且避免內存碎片,RT-Thread 提供了另外一種內存管理方法:內存池(Memory Pool)。內存池(Memory Pool)是一種用于分配大量大小相同的小內存對象的技術。它可以極大加快內存分配/釋放的速度。

1、內存塊分配機制

(1)內存池在創建時先向系統申請一大塊內存,然后分成大小相等的多個小內存塊,小內存塊直接通過鏈表連接起來(此鏈表也稱為空閑內存鏈表)。每次分配的時候,從空閑內存鏈表中取出表頭上第一個內存塊,提供給申請者。物理內存中允許存在多個大小不同的內存池,每一個內存池又由多個大小相同的空閑內存塊組成。當一個內存池對象被創建時,內存池對象就被分配給了一個內存池控制塊,內存控制塊的參數包括內存池名,內存緩沖區,內存塊大小,塊數以及一個等待線程列表。

內存池示意圖(來源[野火?]《RT-Thread 內核實現與應用開發實戰—基于STM32》)

(2)內核負責給內存池分配內存池控制塊,它同時也接收用戶線程的分配內存塊申請,當獲得這些信息后,內核就可以從內存池中為內存池分配內存。內存池一旦初始化完成,內部的內存塊大小將不能再做調整。

2、內存池的管理方式

(1)創建內存池:創建內存池操作將會創建一個內存池對象并從堆上分配一個內存池。創建內存池是從對應內存池中分配和釋放內存塊的先決條件,創建內存池后,線程便可以從內存池中執行申請、釋放等操作。函數接口如下:

1rt_mp_trt_mp_create(constchar*name,2rt_size_tblock_count,3rt_size_tblock_size);

(A)入口參數:name:內存池名。block_count:內存塊數量。block_size:內存塊容量。

(B)返回值:

內存池的句柄:創建內存池對象成功。RT_NULL:創建失敗。

(2)刪除內存池:將刪除內存池對象并釋放申請的內存,刪除內存池時,會首先喚醒等待在該內存池對象上的所有線程(返回 RT_ERROR),然后再釋放已從內存堆上分配的內存池數據存放區域,然后刪除內存池對象。函數接口如下:

1rt_err_trt_mp_delete(rt_mp_tmp);

(A)入口參數:mp:rt_mp_create返回的內存池對象句柄。

(B)返回值:RT_EOK:刪除成功。

(3)初始化內存池:初始化內存池跟創建內存池類似,只是初始化內存池用于靜態內存管理模式,內存池控制塊來源于用戶在系統中申請的靜態對象。另外與創建內存池不同的是,此處內存池對象所使用的內存空間是由用戶指定的一個緩沖區空間,用戶把緩沖區的指針傳遞給內存池控制塊,其余的初始化工作與創建內存池相同。函數接口如下:

1rt_err_trt_mp_init(structrt_mempool*mp,2constchar*name,3void*start,4rt_size_tsize,5rt_size_tblock_size);

(A)入口參數:

mp:內存池對象。name:內存池名。start:內存池的起始位置。size:內存池數據區域大小。block_size:內存塊容量。

(B)返回值:

RT_EOK:初始化成功。RT_ERROR:失敗。

注意:內存池塊個數 = size / (block_size + 4 鏈表指針大小),計算結果取整數。例如:內存池數據區總大小 size 設為 4096 字節,內存塊大小 block_size 設為 80 字節;則申請的內存塊個數為 4096/ (80+4)= 48 個。

(4)脫離內存池:脫離內存池將把內存池對象從內核對象管理器中脫離,內核先喚醒所有等待在該內存池對象上的線程,然后將內存池對象從內核對象管理器中脫離。函數接口如下:

1rt_err_trt_mp_detach(structrt_mempool*mp);

(A)入口參數:

mp:內存池對象。

(B)返回值:

RT_EOK:成功。

(5)分配內存塊:從指定的內存池中分配一個內存塊,函數接口如下:

1void*rt_mp_alloc(rt_mp_tmp,rt_int32_ttime);

(A)入口參數:

mp:內存池對象。

time:超時時間。如果內存池中有可用的內存塊,則從內存池的空閑塊鏈表上取下一個內存塊,減少空閑塊數目并返回這個內存塊;如果內存池中已經沒有空閑內存塊,則判斷超時時間設置:若超時時間設置為零,則立刻返回空內存塊;若等待時間大于零,則把當前線程掛起在該內存池對象上,直到內存池中有可用的自由內存塊,或等待時間到達。

(B)返回值:

分配的內存塊地址:成功。RT_NULL:失敗。

(6)釋放內存塊:任何內存塊使用完后都必須被釋放,否則會造成內存泄露。首先通過需要被釋放的內存塊指針計算出該內存塊所在的(或所屬于的)內存池對象,然后增加內存池對象的可用內存塊數目,并把該被釋放的內存塊加入空閑內存塊鏈表上。接著判斷該內存池對象上是否有掛起的線程,如果有,則喚醒掛起線程鏈表上的首線程。函數接口如下:

1voidrt_mp_free(void*block);

(A)入口參數:block:內存塊指針。

六、基于STM32的內存管理實驗

光說不練都是假把式,那么接下來就行內存管理的實際操作,基于STM32,使用RTT&正點原子聯合出品潘多拉開發板,實現兩個實驗,分別是內存堆管理實驗和內存池實驗。

1、內存堆管理實驗

(1)實現代碼:

1#include"main.h" 2#include"board.h" 3#include"rtthread.h" 4#include"data_typedef.h" 5#include"key.h" 6 7/*線程句柄*/ 8staticrt_thread_tthread1=RT_NULL; 9voiddynmem_sample(void);1011intmain(void)12{13dynmem_sample();14return0;15}1617/**************************************************************18函數名稱:thread1_entry19函數功能:線程1入口函數20輸入參數:parameter:入口參數21返回值:無22備注:無23**************************************************************/24voidthread1_entry(void*parameter)25{26u8key;27char*ptr=RT_NULL;2829while(1)30{31key=key_scan(0);3233if(key==KEY0_PRES)34{35ptr=rt_malloc(10);36if(ptr!=RT_NULL)37{38rt_kprintf("rt_mallocsuccessful\r\n");39sprintf(ptr,"%s","helloRTT");40rt_kprintf("0x%p\r\n",ptr);/*打印分配到的地址*/41rt_kprintf("%s\r\n",ptr);42}43else44{45rt_kprintf("rt_mallocfailed\r\n");46}4748rt_thread_mdelay(2000);4950if(ptr!=RT_NULL)51{52rt_free(ptr);53ptr=RT_NULL;54rt_kprintf("rt_freesuccessful\r\n");55}56else57{58rt_kprintf("rt_freefailed,ptr!=NULL\r\n");59}60}6162rt_thread_mdelay(1);63}64}656667voiddynmem_sample(void)68{69thread1=rt_thread_create("thread1",70thread1_entry,71NULL,72512,733,7420);75if(thread1!=RT_NULL)76{77rt_thread_startup(thread1);;78}79else80{81rt_kprintf("createthread1failed\r\n");82return;83}84}

(2)觀察FinSH,開機按下3次KEY0,如下現象,會打印出申請到內存的地址,2秒后釋放內存:

2、內存池實驗

(1)實現代碼:

1#include"main.h" 2#include"board.h" 3#include"rtthread.h" 4#include"data_typedef.h" 5#include"key.h" 6 7/*線程句柄*/ 8staticrt_thread_tthread2=RT_NULL; 9 10staticrt_mp_tmp; 11 12voidmempool_sample(void); 13 14intmain(void) 15{ 16mempool_sample(); 17 18return0; 19} 20 21/************************************************************** 22函數名稱:thread2_entry 23函數功能:線程2入口函數 24輸入參數:parameter:入口參數 25返回值:無 26備注:無 27**************************************************************/ 28voidthread2_entry(void*parameter) 29{ 30u8key; 31char*ptr=RT_NULL; 32 33while(1) 34{ 35key=key_scan(0); 36 37if(key==KEY1_PRES) 38{ 39ptr=rt_mp_alloc(mp,0); 40if(ptr!=RT_NULL) 41{ 42rt_kprintf("rt_mp_allocsuccessful\r\n"); 43sprintf(ptr,"%s","helloRTT"); 44rt_kprintf("0x%p\r\n",ptr);/*打印分配到的地址*/ 45rt_kprintf("%s\r\n",ptr); 46} 47else 48{ 49rt_kprintf("rt_mp_allocfailed\r\n"); 50} 51 52rt_thread_mdelay(2000); 53 54if(ptr!=RT_NULL) 55{ 56rt_mp_free(ptr); 57ptr=RT_NULL; 58rt_kprintf("rt_mp_freesuccessful\r\n"); 59} 60else 61{ 62rt_kprintf("rt_mp_freefailed,ptr!=NULL\r\n"); 63} 64} 65 66rt_thread_mdelay(1); 67} 68} 69 70 71voidmempool_sample(void) 72{ 73mp=rt_mp_create("mp1",20,20); 74 75if(mp!=RT_NULL) 76{ 77rt_kprintf("mempoolcreatesuccessful\r\n"); 78} 79else 80{ 81rt_kprintf("mempoolcreatefailed\r\n"); 82return; 83} 84 85thread2=rt_thread_create("thread2", 86thread2_entry, 87NULL, 88512, 893, 9020); 91if(thread2!=RT_NULL) 92{ 93rt_thread_startup(thread2);; 94} 95else 96{ 97rt_kprintf("createthread2failed\r\n"); 98return; 99}100101}

(2)觀察FinSH,開機,打印創建mempool成功信息,連續按3次KEY1,打印如下信息,包括申請到內存的地址,2秒后釋放內存:

參考文獻:

1、[野火?]《RT-Thread 內核實現與應用開發實戰—基于STM32》

2、《RT-THREAD 編程指南》

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 函數
    +關注

    關注

    3

    文章

    4327

    瀏覽量

    62573
  • 內存管理
    +關注

    關注

    0

    文章

    168

    瀏覽量

    14134
  • RT-Thread
    +關注

    關注

    31

    文章

    1285

    瀏覽量

    40085

原文標題:社區新人的RT-Thread學習筆記8——內存管理

文章出處:【微信號:RTThread,微信公眾號:RTThread物聯網操作系統】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    C語言內存知識總結:memset函數和calloc函數

    memset(翻譯:清零)是計算機C/C++語言初始化函數。作用是將某一塊內存的內容全部設置
    發表于 10-24 10:40 ?1126次閱讀

    如何使用LWIP標準C內存堆進行操作?

    公司用的RCT6型號,空間不大,想咨詢下大牛們如果我想使用標準C使用內存堆,標準C需要初始化?
    發表于 08-21 22:25

    請問固件函數可以直接調用嗎?

    ;)。。。。。。。。。。。。。。。。。。。。。。想請問一下,固件庫里的函數是不是直接調用就可以?(我是直接調用的,.H文件也加進去了),出現上面的錯誤是不是MDK版本與固件的版本號
    發表于 03-05 04:35

    標準c函數printf進行重定向

    目錄點擊這里查看所有博文2.1、C代碼??由于某些原因我們的elua開源項目中不能采用標準c函數
    發表于 08-20 06:54

    怎樣去實現嵌入式裸機內存動態管理

    嵌入式裸機內存動態管理的實現與講解(一)C標準自帶了malloc和free,為啥還要自己實現?標準
    發表于 12-17 07:02

    AVR單片機C語言

    AVR單片機C語言庫內容目錄: .1. Character Type Functions - 字符類型函數2. Standard C Input/Output Functions - 標準
    發表于 04-22 10:14 ?0次下載
    AVR單片機<b class='flag-5'>C</b>語言<b class='flag-5'>庫</b>

    CodeVisionAVR C語言庫函數介紹

    CodeVisionAVR C語言庫函數介紹 目錄:1. Character Type Functions - 字符類型函數2. Standard C Input/Output Fu
    發表于 04-22 10:17 ?108次下載

    c++標準手冊

    C++的標準手冊,新手學習的好資料,同時也是開發人員的必備手冊。里面涵蓋了標準C++的所有的庫函數
    發表于 11-03 14:05 ?43次下載

    MicroBlaze:malloc 函數動態分配內存溢出

    首先說明一點,MicroBlaze C函數庫支持標準內存管理函數,如malloc(),call
    發表于 02-11 11:43 ?1922次閱讀
    MicroBlaze:malloc <b class='flag-5'>函數</b>動態分配<b class='flag-5'>內存</b>溢出

    linux_C函數庫中文手冊

    linux_C函數庫中文手冊linux_C函數庫中文手冊
    發表于 03-20 10:42 ?14次下載

    標準函數是什么_標準函數有哪些

    在程序設計,常將一些常用的功能模塊編寫成的函數放在函數庫供公共選用,一般稱為標準函數。程序是
    的頭像 發表于 03-02 10:24 ?9265次閱讀
    <b class='flag-5'>標準</b><b class='flag-5'>函數</b>是什么_<b class='flag-5'>標準</b><b class='flag-5'>函數</b>有哪些

    標準C函數庫的用法

    C標準函數庫是所有符合標準的頭文件的集合,以及常用的函數庫實現程序,例如I/O 輸入輸出和字符串控制。不像 COBOL、Fortran 和
    的頭像 發表于 03-02 11:27 ?5212次閱讀
    <b class='flag-5'>標準</b><b class='flag-5'>C</b><b class='flag-5'>函數庫</b>的用法

    C語言常用標準分享

    有很多工程師喜歡自己封裝一些標準已有的函數,其實自己封裝的函數,并不一定比標準好,有時候反而
    的頭像 發表于 02-20 18:08 ?1049次閱讀

    FreeRTOS內存管理簡介

    ,比如任務創建函數 xTaskCreateStatic(),使用此函數創建任務的時候需要由用戶定義任務堆棧,我們討論這種靜態方法。 使用動態內存
    的頭像 發表于 07-30 10:26 ?670次閱讀

    C語言中的動態內存管理講解

    本章將講解 C 的動態內存管理。C 語言為內存的分配和管理
    的頭像 發表于 02-23 14:03 ?390次閱讀
    <b class='flag-5'>C</b>語言中的動態<b class='flag-5'>內存</b><b class='flag-5'>管理</b>講解
    主站蜘蛛池模板: 久久免费特黄毛片| 久久re视频这里精品一本到99| 国内精品久久久久久久999下| 久久久久亚洲精品影视| 欧美亚洲日韩自拍高清中文| 校园男男高h小黄文| 91av成年影院在线播放| 国产成人mv 在线播放| 久久精品AV无码亚洲色欲| 日本不卡三卡四卡| 亚洲在线2018最新无码| 高hnp全肉| 久久极品视频| 色欲AV蜜臀AV在线观看麻豆| 这里只有精品在线视频| 丰满的女朋友韩国版在线观看 | 不卡无线在一二三区| 韩国伦理片2018在线播放免费观看| 欧美高清videosgratis高| 亚洲精品免费在线视频| 被同桌摸出水来了好爽的视频| 久久成人精品免费播放| 王晶三级作品| avove主播| 精品一二三区久久AAA片| 国产色精品久久人妻99蜜桃麻豆| 激情床戏视频片段有叫声| 四虎影院2022| 羞羞在线观看| 成人毛片免费观看视频大全| 久草视频在线观看免费4| 手机免费毛片| yellow免费观看完整版直播| 久久亚洲AV无码精品午色夜麻豆 | 三级中国免费的| 91久久综合精品国产丝袜长腿| 好看的电影网站亚洲一区| 熟妇少妇任你躁在线无码| 99视频全部看免费观| 久久一级视频| 一本色道久久88加勒比—综合|