微控制器上記憶體管理(重定義malloc & free)de實現
阿新 • • 發佈:2019-02-06
在微控制器上經常會需要用到像標準c庫中的記憶體分配,可是微控制器並沒有記憶體管理機制,如果直接呼叫庫函式(malloc,free...),會導致記憶體碎片越用越多,很容易使系統崩潰掉,這裡分享一個自己寫的適用於微控制器的記憶體分配方法,具備輕量級的記憶體管理能力,有效減少記憶體碎片,提高微控制器系統工作穩定性。
如下圖,heap_start開始的地方,是我們存放使用者資料的地方,在heap_end之前都是大小固定的一個個記憶體管理塊,記憶體管理塊用於記錄每次使用者申請記憶體的地址、大小、釋放情況。在malloc時,會優先選擇和使用者申請空間最相當的記憶體塊,以減少記憶體碎片產生。在free的記憶體塊時,如果遇到相鄰記憶體塊均為空閒塊時,便會將幾塊相鄰的記憶體塊合併成一塊,以減少記憶體碎片。
原始碼下載:
alloc.c
/* ******************************************************************************** * memory alloc * * (c) Copyright 2018-2020; * All rights reserved. Protected by international copyright laws. * * MEMORY ALLOC * * File : mem_alloc.c * By : Recahrd.Zhang * Version : V1.00 * ******************************************************************************** */ #include <string.h> #include "mem_alloc.h" #include "debug.h" #define MEM_ALLOC 1 #if defined (MEM_ALLOC)&&MEM_ALLOC #define alloc_printf printf #else #define alloc_printf(argv, ...) #endif #define MEM_SIZE 2*1024 /*記憶體池的大小 2 KBytes*/ static char mem[MEM_SIZE]; /*定義用來記憶體分配的陣列*/ #define MEM_START &mem[0] /*定義記憶體池的首地址*/ #define MEM_END &mem[MEM_SIZE] /*定義記憶體池的尾地址*/ enum USE_STA{ /*定義記憶體塊的使用狀態(UNUSED 未使用),(USED 已使用)*/ UNUSED = 0, USED = 1 }; #pragma pack(1) typedef struct mem_block{ /*定義記憶體管理塊的資料結構*/ void *mem_ptr; /*當前記憶體塊的記憶體地址*/ struct mem_block *nxt_ptr; /*下一個記憶體管理塊的地址*/ unsigned int mem_size; /*當前記憶體塊的大小*/ enum USE_STA mem_sta; /*當前記憶體塊的狀態*/ }mem_block; #pragma pack() #define BLK_SIZE sizeof(mem_block) /*記憶體管理塊的大小*/ #define HEAD_NODE (MEM_END - BLK_SIZE)/*頭記憶體管理塊的地址*/ static signed char mem_init_flag = -1; /*記憶體分配系統初始化的標誌(-1 未初始化),(1 已初始化)*/ /* ******************************************************************************** * 記憶體分配系統初始化 * * 描述 : 初始化記憶體分配系統,為malloc和free做好準備工作。 * * 引數 : 無 * * 返回 : 無 ******************************************************************************** */ void mem_init(void) { mem_block *node; memset(mem, 0x00UL, sizeof(mem)); node = (mem_block *)HEAD_NODE; node->mem_ptr = MEM_START; node->nxt_ptr = (mem_block *)HEAD_NODE; node->mem_size = MEM_SIZE - BLK_SIZE; node->mem_sta = UNUSED; mem_init_flag = 1; } /* ******************************************************************************** * 記憶體申請函式 * * 描述 : 記憶體申請函式 * * 引數 : nbytes 要申請的記憶體的位元組數。 * * 返回 : 成功 返回申請到的記憶體的首地址 * 失敗 返回NULL ******************************************************************************** */ static void *malloc(unsigned nbytes) { unsigned int suit_size = 0xFFFFFFFFUL; mem_block *head_node=NULL, *tmp_node=NULL, *suit_node=NULL; if(nbytes == 0) { alloc_printf("引數非法!\r\n"); return NULL; } if(mem_init_flag < 0) { alloc_printf("未初始化,先初始化.\r\n"); mem_init(); } head_node = tmp_node = (mem_block *)HEAD_NODE; while(1) { if(tmp_node->mem_sta == UNUSED) { if(nbytes <= tmp_node->mem_size && tmp_node->mem_size < suit_size) { suit_node = tmp_node; suit_size = suit_node->mem_size; } } tmp_node = tmp_node->nxt_ptr; if(tmp_node == head_node) { if(suit_node == NULL) { alloc_printf("NULL\r\n"); return NULL; } break; } } if(nbytes <= suit_node->mem_size && (nbytes + BLK_SIZE) >= suit_node->mem_size) { suit_node->mem_sta = USED; return suit_node->mem_ptr; } else if(suit_node->mem_size > (nbytes + BLK_SIZE)) { tmp_node = suit_node->mem_ptr; tmp_node = (mem_block *)((unsigned char *)tmp_node + nbytes); tmp_node->mem_ptr = suit_node->mem_ptr; tmp_node->nxt_ptr = suit_node->nxt_ptr; tmp_node->mem_size = nbytes; tmp_node->mem_sta = USED; suit_node->mem_ptr = (mem_block *)((unsigned char *)tmp_node + BLK_SIZE); suit_node->nxt_ptr = tmp_node; suit_node->mem_size -= (nbytes + BLK_SIZE); suit_node->mem_sta = UNUSED; return tmp_node->mem_ptr; } else { alloc_printf("%s,size err!\r\n",__FUNCTION__); } return NULL; } /* ******************************************************************************** * 記憶體釋放函式 * * 描述 : 記憶體釋放函式 * * 引數 : ap 要釋放的記憶體塊的指標。 * * 返回 : 無 ******************************************************************************** */ static void free(void *ap) { mem_block *head_node, *tmp_node, *nxt_node; if(ap == NULL) return; if(mem_init_flag < 0) { return; } head_node = tmp_node = (mem_block *)HEAD_NODE; while(1) { if(tmp_node->mem_ptr == ap) { if(tmp_node->mem_sta != UNUSED) { tmp_node->mem_sta = UNUSED; break; } else { alloc_printf("ap:0x%08x 已經釋放,無需再次釋放\r\n",ap); return; } } tmp_node = tmp_node->nxt_ptr; if(tmp_node == head_node) { alloc_printf("%s,can not found ap!\r\n",__FUNCTION__); return ; } } AGAIN: head_node = tmp_node = (mem_block *)HEAD_NODE; while(1) { nxt_node = tmp_node->nxt_ptr; if(nxt_node == head_node) { break; } if(tmp_node->mem_sta == UNUSED && nxt_node->mem_sta == UNUSED) { tmp_node->mem_ptr = nxt_node->mem_ptr; tmp_node->nxt_ptr = nxt_node->nxt_ptr; tmp_node->mem_size += nxt_node->mem_size + BLK_SIZE; tmp_node->mem_sta = UNUSED; goto AGAIN; } tmp_node = nxt_node; } } void *m_malloc(unsigned nbytes) { return malloc(nbytes); } void m_free(void *ap) { free(ap); }
alloc.h
#ifndef __MEM_ALLOC_H__
#define __MEM_ALLOC_H__
void *m_malloc(unsigned nbytes);
void m_free(void *ap);
#endif
test.c:
#include <stdio.h> #include "alloc.h" #define alloc_printf pritnf /* ******************************************************************************** * 記憶體列印函式 * * 描述 : 列印記憶體系統中每一個記憶體塊的資訊 * * 引數 : 無 * * 返回 : 無 ******************************************************************************** */ void mem_print(void) { unsigned int i = 0; mem_block *head_node, *tmp_node; if(mem_init_flag < 0) { alloc_printf("未初始化,先初始化.\r\n"); mem_init(); } head_node = tmp_node = (mem_block *)HEAD_NODE; alloc_printf("\r\n#############################\r\n"); while(1) { alloc_printf("\r\nNO.%d:\r\n",i++); alloc_printf("blk_ptr:0x%08x\r\n",tmp_node); alloc_printf("mem_ptr:0x%08x\r\n",tmp_node->mem_ptr); alloc_printf("nxt_ptr:0x%08x\r\n",tmp_node->nxt_ptr); alloc_printf("mem_size:%d\r\n",tmp_node->mem_size); alloc_printf("mem_sta:%d\r\n",tmp_node->mem_sta); tmp_node = tmp_node->nxt_ptr; if(tmp_node == head_node) { break; } } alloc_printf("\r\n#############################\r\n"); } void buff_print(unsigned char *buf,unsigned int len) { unsigned int i; alloc_printf("\r\n"); for(i=0;i<len;i++) { if(i%16 == 0 && i != 0) { alloc_printf("\r\n"); } alloc_printf("0x%02x,",buf[i]); //alloc_printf("%c",buf[i]); } alloc_printf("\r\n"); } void *m_malloc(unsigned nbytes) { return malloc(nbytes); } void m_free(void *ap) { free(ap); } typedef char (*array)[4]; /* ******************************************************************************** * 記憶體分配函式測試 * * 描述 : 測試記憶體分配系統中每一個函式的功能 * * 引數 : 無 * * 返回 : 無 ******************************************************************************** */ void alloc_test(void) { array ptr = NULL; unsigned int i,j; alloc_printf("Ptr1:%d\r\n",sizeof(ptr)); ptr = m_malloc(16); if(ptr == NULL) { alloc_printf("malloc failed.\r\n"); return; } mem_print(); for(i=0;i<4;i++) { for(j=0;j<4;j++) { ptr[i][j] = i; } } m_free(ptr); mem_print(); buff_print((unsigned char *)ptr, 16); }