单片机应用中,malloc/free产生内存碎片的原因:
标准内存动态分配是动态链表进行管理。由于malloc返回的是一个指针再加上单片机没有mmu,使得分配的指针就像一个个钉子钉在内存中了。这就导致内存管理非常困难,从而产生我们常说的内存碎片。 我们来举一个极端的例子,导致大量内存碎片: 1. 单片机的RAM为1Kbyte,为了说明和计算方便我们忽略掉链表占用的空间,只计算实际存储空间大小。 2. 申请64块内存空间,每块是16字节,那么就会分配完1k字节的空间。即:
for(int i=0; i<64; i++){
ptr = malloc(16);
} 3. 然后释放掉偶数块内存空间,即:
for(int i=0; i<64; i+=2){
free(ptr );
} 4. 于是我们释放掉了一半的RAM空间,即有512字节的空间,但是都是非连续的。32块16字节的非连续空间,所以要分配出大于16字节的内存块是分配不出来的。有512字节的空间但只能分配小于16字节的连续空间(除非使用calloc分配非连续空间),在某些场合原本单片机RAM空间就很急,再加上这种不充分的使用使得程序稳定性大打折扣。 鉴于各中原因本人自己编写了一个内存管理,适合单片机使用的内存管理分配。 算法原理:
定义一个数组作为动态分配的堆空间,低地址空间保存管理数据,高地址空间实际分配给用户的缓存(类似堆栈使用,分配是往中间靠拢),free时移动高地址用户空间(以时间换空间),腾出多余未使用的空间,等待malloc来分配。 - #include "mem_malloc.h"
- static unsigned int sum = 0;
- static char mem[MEM_SIZE];
- #define DEBUG_EN 0
- #define MEM_START &mem[0]
- #define MEM_END &mem[MEM_SIZE]
- #define BLK_SIZE sizeof(mem_block)
- void print_mem_info(void){
- printf("------------mem_info--------------\n");
- printf("sizeof(mem_block)=%d\n", BLK_SIZE);
- printf("MEM_START = %d(0x%x)\n", (int)MEM_START, (int)MEM_START);
- printf("MEM_END = %d(0x%x)\n", (int)MEM_END, (int)MEM_END);
- printf("MEM_SIZE = %d(0x%x)\n", (int)MEM_SIZE, (int)MEM_SIZE);
- printf("----------------------------------\n");
- }
- void print_hex(char *data, int len){
- for(int i=0; i<len; i++){
- printf("%02x ", (unsigned char)data[i]);
- if((i+1)%12 == 0) printf("\n");
- }
- printf("\n");
- }
- void print_mem_hex(int size){
- print_hex(mem, size);
- }
- int mem_malloc(unsigned int msize){
- unsigned int all_size = msize + sizeof(mem_block);
- mem_block tmp_blk;
- if(msize == 0) return 0;
- if(sum){
- mem_block *ptr_blk = (mem_block *)(MEM_START + BLK_SIZE*(sum-1));
- int free_blk = (char *)ptr_blk->mem_ptr-(MEM_START + BLK_SIZE*sum);
- if(all_size <= free_blk){
- tmp_blk.mem_ptr = ptr_blk->mem_ptr - msize;
- tmp_blk.mem_size = msize;
- tmp_blk.mem_index = ptr_blk->mem_index + 1;
- memcpy(MEM_START + BLK_SIZE*sum, &tmp_blk, BLK_SIZE);
- sum = sum + 1;
- #if DEBUG_EN
- printf("mem_ptr = 0x%x\n", (int)tmp_blk.mem_ptr);
- printf("mem_size = 0x%x\n", tmp_blk.mem_size);
- printf("mem_index = 0x%x\n", tmp_blk.mem_index);
- #endif
- return tmp_blk.mem_index;
- }
- }else{
- if(all_size <= MEM_SIZE){
- tmp_blk.mem_ptr = MEM_END - msize;
- tmp_blk.mem_size = msize;
- tmp_blk.mem_index = 1;
- memcpy(MEM_START, &tmp_blk, BLK_SIZE);
- sum = 1;
- #if DEBUG_EN
- printf("mem_ptr = 0x%x\n", (int)tmp_blk.mem_ptr);
- printf("mem_size = 0x%x\n", tmp_blk.mem_size);
- printf("mem_index = 0x%x\n", tmp_blk.mem_index);
- #endif
- return 1;
- }
- }
- return 0;
- }
- void *mem_buffer(int id){
- for(int i=0; i<sum; i++){
- mem_block *ptr_blk = (mem_block *)(MEM_START + BLK_SIZE*i);
- if(id == ptr_blk->mem_index){
- return ptr_blk->mem_ptr;
- }
- }
- return NULL;
- }
- void mem_free(int id){
- for(int i=0; i<sum; i++){
- mem_block *ptr_blk = (mem_block *)(MEM_START + BLK_SIZE*i);
- if(id == ptr_blk->mem_index){
- mem_block *ptr_old;
- if(i != (sum-1)){
- int offset = ptr_blk->mem_size;
- int move_size = 0;
- int n = sum - i;
- mem_block *ptr_tmp;
- for(int j=1; j<n; j++){
- ptr_tmp = (mem_block *)(MEM_START + BLK_SIZE*(i+j));
- move_size += ptr_tmp->mem_size;
- }
- //memmove();
- char *dst_addr = ptr_tmp->mem_ptr + move_size + offset - 1;
- char *src_addr = ptr_tmp->mem_ptr + move_size - 1;
- for(int j=move_size; j>0; j--){
- *dst_addr-- = *src_addr--;
- }
- int len = dst_addr - src_addr + 1;
- memset(src_addr, 0, len);
- for(int j=0; j<(n-1); j++){
- ptr_tmp = (mem_block *)(MEM_START + BLK_SIZE*(i+j));
- ptr_old = (mem_block *)(MEM_START + BLK_SIZE*(i+j+1));
- memcpy(ptr_tmp, ptr_old, BLK_SIZE);
- ptr_tmp->mem_ptr += offset;
- }
- }else{
- ptr_old = (mem_block *)(MEM_START + BLK_SIZE*i);
- memset(ptr_old->mem_ptr, 0, ptr_old->mem_size);
- }
- memset(ptr_old, 0, BLK_SIZE);
- sum = sum - 1;
- break;
- }
- }
- }
源码:https://github.com/chenqy2018/mem_malloc
|