【STM32】內存管理
文章目錄
- 【STM32】內存管理
- 1、內存管理簡介
- 疑問:為啥不用標準的 C 庫自帶的內存管理算法?
- 2、分塊式內存管理(掌握)
- 分配方向
- 分配原理
- 釋放原理
- 分塊內存管理 管理內存情況
- 3、內存管理使用(掌握)
- 操作步驟
- 內存池
- 內存管理表
1、內存管理簡介
如何在LCD 上面實現SD卡文件瀏覽?
需要讀取所有文件名到內存,然后顯示到LCD。一般的方法,是定義一個數組來存儲所有文件名
1,需要知道最大文件名的長度。255字節。
2,需要知道文件個數。 100?1000?10000 ?
如果沒有內存管理:則要定義一個:uint8_t filenametbl[10000][255]; 的數組!(占用2550K字>節內存)
內存管理,是指軟件運行時對MCU內存資源的分配和使用的技術。(內存的大管家)
其最主要目的是:如何高效,快速的分配,并且在適當的時候釋放和回收內存資源。(防止內存泄露、內存碎片)
內存使用三部曲:1. 內存申請(分配) 2. 內存使用 3.內存釋放
內存管理的實現方法有很多種,最終都是實現2個函數:malloc和free;
malloc | 內存申請 |
---|---|
free | 內存釋放 |
標準的 C 庫也提供了函數 malloc()和函數 free()來實現動態地申請和釋放內存 。
疑問:為啥不用標準的 C 庫自帶的內存管理算法?
因為標準 C 庫的動態內存管理方法有如下幾個缺點:
- 占用大量的代碼空間 不適合用在資源緊缺的嵌入式系統中
- 沒有線程安全的相關機制
- 運行有不確定性,每次調用這些函數時花費的時間可能都不相同
- 內存碎片化
- ………
2、分塊式內存管理(掌握)
分塊式內存管理由內存池和內存管理表兩部分組成。內存池被等分為n塊,對應的內存管理表,大小也為n,內存管理表的每一個項對應內存池的一塊內存。
內存管理表的項值代表的意義:當該項值為0時,代表對應的內存塊未被占用;當該項值非零時,代表該項對應的內存塊已經被占用,其數值則代表被連續占用的內存塊數。
當內存管理剛初始化的時候,內存管理表全部清零,表示沒有任何內存塊被占用。
分配方向
分配原理
當指針p調用malloc申請內存時,
① 先判斷p要分配的內存塊數(m)
② 從第n項開始,向下查找,直到找到m塊連續的空內存塊(即對應內存管理表項為0)
③ 將這m個內存管理表項的值都設置為m(標記被占用)
④ 把最后的這個空內存塊的地址返回指針p,完成一次分配
注意:如果當內存不夠時(找到最后也沒有找到連續m塊空閑內存),則返回NULL給p,表示分配失敗。
釋放原理
當指針p申請的內存用完,需要釋放的時候,調用free函數實現。
free函數實現:
① 先判斷p指向的內存地址所對應的內存塊
② 找到對應的內存管理表項目,得到p所占用的內存塊數目m
③ 將這m個內存管理表項目的值都清零,標記釋放,完成一次內存釋放
分塊內存管理 管理內存情況
3、內存管理使用(掌握)
操作步驟
1、初始化內存
內存管理控制器 struct _m_malloc_dev
外擴SRAM 需初始化(內部SRAM不需要)
內存管理表 清零 void my_mem_init(uint8_t memx)
2、申請內存
void *mymalloc(uint8_t memx, uint32_t size)
3、操作內存
sprintf((char *)p, “Memory Malloc Test%03d”, i);
4、釋放內存(用完,一定要釋放)
void myfree(uint8_t memx, void *ptr)
/* 內存管理控制器 */
#define SRAMBANK 2 /* 定義管理的內存片數*/
struct _m_mallco_dev
{void (*init)(uint8_t); /* 函數指針,指向內存初始化函數,用于初始化內存管理 */uint8_t (*perused)(uint8_t); /* 函數指針,指向內存使用率函數,用于獲取內存使用率 */uint8_t *membase[SRAMBANK]; /* 內存池指針,指向內存池 */uint16_t *memmap[SRAMBANK]; /* 內存管理表指針,指向內存管理表 */uint8_t memrdy[SRAMBANK]; /* 內存管理表就緒標志,用于表示內存管理表是否已初始化 */
};
struct _m_mallco_dev mallco_dev
{my_mem_init, my_mem_perused, mem1base, mem2base, mem1mapbase, mem2mapbase, 0, 0,
};MEMx_MAX_SIZE 內存池中內存塊大小
MEMx_ALLOC_TABLE_SIZE 內存管理表中項數
/* 內存池 */
static __align(64) uint8_t mem1base[MEM1_MAX_SIZE];
static __align(64) uint8_t mem2base[MEM2_MAX_SIZE];
/* 內存管理表 */
static uint16_t mem1mapbase[MEM1_ALLOC_TABLE_SIZE];
static uint16_t mem2mapbase[MEM2_ALLOC_TABLE_SIZE];
內存池
uint8_t mem1base[MEM1_MAX_SIZE]
MEM1_ALLOC_TABLE_SIZE個內存塊
內存管理表
uint16_t mem1mapbase[MEM1_ALLOC_TABLE_SIZE]
MEM1_ALLOC_TABLE_SIZE個項
項的大小為2字節
void my_mem_init(uint8_t memx)
{uint8_t mttsize = sizeof(MT_TYPE); /* 獲取memmap數組的類型長度(uint16_t /uint32_t)*/my_mem_set(mallco_dev.memmap[memx], 0, memtblsize[memx] * mttsize); /* 內存管理表數據清零 */mallco_dev.memrdy[memx] = 1; /* 內存管理初始化OK */
}
uint16_t my_mem_perused(uint8_t memx)
{uint32_t i, used = 0;for (i = 0; i < memtblsize[memx]; i++)if (mallco_dev.memmap[memx][i])used++;return (used * 1000) / (memtblsize[memx]);
}
void my_mem_set(void *s, uint8_t c, uint32_t count)
{uint8_t *xs = s;while (count--) *xs++ = c;
}
void *mymalloc(uint8_t memx, uint32_t size)
{uint32_t offset; offset = my_mem_malloc(memx, size);if (offset == 0xFFFFFFFF) return NULL; /* 申請出錯 */else return (void *)((uint32_t)mallco_dev.membase[memx] + offset); /* 申請沒問題,返回首地址 */
}
uint32_t my_mem_malloc(uint8_t memx, uint32_t size)
{/* 1、判斷內存塊memx是否已經初始化 *//* 2、通過size獲取需要分配的連續內存塊數x *//* 3、搜索符合 要求內存塊數x 的內存塊 *//* 4、找到符合要求內存塊數區域,對其管理表寫入內存塊數的值x,返回偏移地址 */
}