自写单片机malloc,高效利用ram,不再有内存碎片_单片机调用malloc会有碎片

85 阅读9分钟

for(int i=0; i<64; i+=2){
free(ptr[i] );
}

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; 
                }
        }
}

main.c

#include "mem_malloc.h"

char mem_id[10]={0};

void test_malloc(int i, int size){
	printf("------test_malloc-------\n");
	mem_id[i] = mem_malloc(size);
	if(mem_id[i] == 0){
		printf("malloc --- fail\n");
		printf("size=%d\n", size);
	}else{
		char *p = mem_buffer(mem_id[i]);
        memset(p, i, size);
        printf("p = 0x%x, id=%d, size=%d\n", (int)p, mem_id[i], size);
	}
	print_mem_hex(MEM_SIZE);
}

void test_buffer(int i, int size){
	printf("------test_buffer-------\n");
	printf("id = %d, size=%d\n", mem_id[i], size);
	char *p = mem_buffer(mem_id[i]);
    if(p != NULL){
		memset(p, 0xf0+i, size);
        print_mem_hex(MEM_SIZE);
	}
}

void test_free(int id){
	printf("------test_free-------\n");
	printf("id = %d\n", mem_id[id]);
	mem_free(mem_id[id]);
	print_mem_hex( MEM_SIZE);
}

void main(void){

	print_mem_info();
	test_malloc(1, 10);
	test_malloc(2, 8);
	test_malloc(3, 20);
	test_free(2);
	test_malloc(4, 10);
	test_free(1);
	test_malloc(5, 20);
	test_malloc(6, 10);
	test_malloc(7, 10);
	test_free(6);
	test_malloc(8, 13);
	test_buffer(5, 20);
	test_free(4);
	test_buffer(3, 20);
	test_malloc(9, 15);
	test_malloc(10, 15);
} 

结果:

------------mem_info--------------
sizeof(mem_block)=12
MEM_START = 134525056(0x804b080)
MEM_END   = 134525184(0x804b100)
MEM_SIZE  = 128(0x80)    //方便演示以128字节空间测试

------test_malloc-------
p = 0x804b0f6, id=1, size=10
f6 b0 04 08 0a 00 00 00 01 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 01 01 
01 01 01 01 01 01 01 01                       //第一次分配的10个字节空间
------test_malloc-------
p = 0x804b0ee, id=2, size=8
f6 b0 04 08 0a 00 00 00 01 00 00 00 
ee b0 04 08 08 00 00 00 02 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 
00 00 02 02 02 02 02 02 02 02 01 01   // 第二次分配的8个字节空间
01 01 01 01 01 01 01 01 
------test_malloc-------
p = 0x804b0da, id=3, size=20
f6 b0 04 08 0a 00 00 00 01 00 00 00 
ee b0 04 08 08 00 00 00 02 00 00 00 
da b0 04 08 14 00 00 00 03 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 03 03 03 03 03 03 
03 03 03 03 03 03 03 03 03 03 03 03   //第三次分配的20个字节空间
03 03 02 02 02 02 02 02 02 02 01 01 
01 01 01 01 01 01 01 01 
------test_free-------
id = 2
f6 b0 04 08 0a 00 00 00 01 00 00 00 
e2 b0 04 08 14 00 00 00 03 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 
00 00 03 03 03 03 03 03 03 03 03 03 
03 03 03 03 03 03 03 03 03 03 01 01  //释放掉了第二次分配的8字节空间
01 01 01 01 01 01 01 01 
------test_malloc-------
p = 0x804b0d8, id=4, size=10
f6 b0 04 08 0a 00 00 00 01 00 00 00 
e2 b0 04 08 14 00 00 00 03 00 00 00 
d8 b0 04 08 0a 00 00 00 04 00 00 00
 
00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 04 04 04 04 04 04 04 04  //第四次分配10字节空间
04 04 03 03 03 03 03 03 03 03 03 03 
03 03 03 03 03 03 03 03 03 03 01 01 
01 01 01 01 01 01 01 01 
------test_free-------
id = 1
ec b0 04 08 14 00 00 00 03 00 00 00 
e2 b0 04 08 0a 00 00 00 04 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 
00 00 04 04 04 04 04 04 04 04 04 04 
03 03 03 03 03 03 03 03 03 03 03 03 
03 03 03 03 03 03 03 03                       //释放掉了第一次分配的10字节空间
------test_malloc-------
p = 0x804b0ce, id=5, size=20
ec b0 04 08 14 00 00 00 03 00 00 00 
e2 b0 04 08 0a 00 00 00 04 00 00 00 
ce b0 04 08 14 00 00 00 05 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 05 05 05 05 05 05 
05 05 05 05 05 05 05 05 05 05 05 05  //第五次分配20字节空间
05 05 04 04 04 04 04 04 04 04 04 04 
03 03 03 03 03 03 03 03 03 03 03 03 
03 03 03 03 03 03 03 03 
------test_malloc-------
p = 0x804b0c4, id=6, size=10
ec b0 04 08 14 00 00 00 03 00 00 00 
e2 b0 04 08 0a 00 00 00 04 00 00 00 
ce b0 04 08 14 00 00 00 05 00 00 00 
c4 b0 04 08 0a 00 00 00 06 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 06 06 06 06   //第六次分配10字节空间
06 06 06 06 06 06 05 05 05 05 05 05 
05 05 05 05 05 05 05 05 05 05 05 05 
05 05 04 04 04 04 04 04 04 04 04 04 
03 03 03 03 03 03 03 03 03 03 03 03 
03 03 03 03 03 03 03 03 
------test_malloc-------
malloc --- fail
size=10
**ec b0 04 08 14 00 00 00 03 00 00 00 

收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。 img img

如果你需要这些资料,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!