使用此管理方式:
#define RT_USING_MEMPOOL
- 分配記憶體的時間需固定,而且可確定(可預測)的
- 分配記憶體同時也要盡量避免碎片化,才能減少系統需重啟的次數
- RT-Thread 使用了靜態與動態管理,其中動態又分為小記憶體管理,與大記憶體管理(SLAB)
- mempool 的管理方法(靜態管理):
- 從 RAM 中要一塊記憶體
- 將此記憶體切成固定大小的區塊
- 以間接定址的方式接起來,形成 free list
結構#
File: redef.h
736 |
|
我們從文本的圖來解釋結構:
start_address
為每個 mempool 的起始位置,此圖為例則為mempool 1 的起始位置size
為 mempool 的大小,此圖為例則為mempool 1 的大小(灰色區塊)block_size
為由 mempool 產出的空閒鏈表中,每一塊的大小,以mempool 1 為例,則為 32kblock_list
為空閒鏈表,此圖為例則為mempool 1 旁邊的鏈結block_total_count
為空閒鏈表創建時的總塊數,以mempool 1 為例,則為 128block_free_count
為為空閒鏈表現在可用的總塊數suspend_thread
則為等待隊伍,此圖為例為最右邊的鏈結suspend_thread_count
則為等待隊伍的總排隊數,以此圖為例為 3
File: mempool.c
建立 memory pool#
- 建立 memory pool 的方法一樣也可分為靜態的與動態的
- 這裡的動態是指從原先記憶體 heap 的區塊拿取記憶體
動態#
功能 | 回傳值 |
---|---|
建立 mempool(使用 heap) | mempool |
*name |
block_count |
block_size |
---|---|---|
名字 | 要切割的總塊數 | 一塊 free block 的大小 |
174 | /** |
- 首先一樣先從 heap 取一塊記憶體作為 mempool 使用
199 | /* initialize memory pool */ |
- 接著對齊
block_size
後填入結構中,一併計算 mempool 的大小 - 並從 heap 中取出一塊待會做成 free list
214 | mp->block_total_count = block_count; |
- 填入總數,建立等待鏈
220 | /* initialize free block list */ |
- 最後製作 free list:
- 一個 free block 分成兩部分:前 8-bit (rt_uint8_t *)與一個 block_size
- 前 8-bit 存放下一個 free block 的位置
靜態#
- 多傳了兩個參數
size
與*start
功能 | 回傳值 |
---|---|
建立 mempool | RT_EOK |
*mp |
*name |
*start |
---|---|---|
結構位址 | 名字 | 所要使用的記憶體位址 |
size |
block_size |
---|---|
mempool 大小 | 一塊 free block 的大小 |
65 | /** |
- 可直接用
rt_object_init
初始化物件 - 同時用
RT_ALIGN_DOWN
對齊 size - 填入
block_size
RT_ALIGN_DOWN
v.s. RT_ALIGN
- 當傳入 (13,4) 時:
RT_ALIGN_DOWN
回傳 12,也就是在不超過 13 中,4 的倍數中最大的RT_ALIGN
回傳 16,也就是在大於等於 13 中,4 的倍數中最小的
99 | /* align to align size byte */ |
- 接著手動算出 block 的總數
102 | /* initialize suspended thread list */ |
- 其他的動作皆相同
刪除 memory pool#
動態#
功能 | 回傳值 | mp |
---|---|---|
刪除 mempool(使用 heap) | RT_EOK |
欲刪除的 mempool |
241 | /** |
- 當要把 mempool 刪除前,先將正在等待分配記憶體的 thread 一個一個叫醒
- 叫醒前,先將錯誤碼改成
ERROR
270 | /* |
- 接著透過
rt_thread_resume
叫醒 thread
從等待鏈上移出的動作,在 rt_thread_resume
中會實現。
(code in RT-Thread Thread)
276 | /* decrease suspended thread count */ |
- 最後更新
suspend_thread_count
282 | /* release allocated room */ |
- 叫醒完,free 掉建立 mempool 時所要的記憶體
- 再透過
rt_object_delete
刪除
靜態#
功能 | 回傳值 | *mp |
---|---|---|
刪除 mempool | RT_EOK |
欲刪除的 mempool |
125 | /** |
- 如果是靜態的,就不需要 free
Code: allocate#
功能 | 回傳值 |
---|---|
分配記憶體 | 一塊 free block |
mp |
time |
---|---|
mempool | 等待時間 |
296 | /** |
- 如果目前無法取得記憶體,且等待時間為 0,回傳 NULL,並設置錯誤碼為 TIMEOUT
329 | RT_DEBUG_NOT_IN_INTERRUPT; |
- 如果需要等待,啟動一個 timer
349 | /* enable interrupt */ |
- 並做一次調度
354 | if (thread->error != RT_EOK) |
- 最後更新 time 值
366 | /* memory block is available. decrease the free block counter */ |
- 如果可以要記憶體,更新
block_free_count
368 | /* get block from block list */ |
- 取得第一顆
371 | /* Setup the next free node. */ |
- 並將 free list 往後一顆
block_list
是使用間接定址,前 8-bit 是下一顆的位置
373 | /* point to memory pool */ |
- 接著將前 8-bit 指向原來的 mempool
375 | /* enable interrupt */ |
-
最後回傳取得的 free block
-
注意這裡回傳的是
block_ptr + 8
,也就是真正可以使用的位址 -
如果要尋找這個 block 所屬的 mempool 則需要 -8。
Code: free#
功能 | 回傳值 | *block |
---|---|---|
釋放記憶體 | void | 所要釋放的記憶體塊 |
393 | /** |
- 首先取得所屬的 mempool(-8)
408 | RT_OBJECT_HOOK_CALL(rt_mp_free_hook, (mp, block)); |
- 更新
block_free_count
- 接著定址到 free list,重新指定 block list
- 也就是將此 block 插到第一顆
419 | if (mp->suspend_thread_count > 0) |
- 如果有人在等資源,叫醒他,並做一次調度