一.原理解说
内存管理,是指软件运行时对计算机内存资源的分配和使用的技术。其最主要的目的是如 何高效,快速的分配,并且在适当的时候释放和回收内存资源。内存管理的实现方法有很多种, 他们其实最终都是要实现 2 个函数:malloc 和 free;malloc 函数用于内存申请,free 函数用于内存释放。
我们介绍一种比较简单的办法来实现:分块式内存管理。下面我们介绍一下该方法的实现原理。

从上图可以看出,分块式内存管理由内存池和内存管理表两部分组成。内存池被等分为 n 块,对应的内存管理表,大小也为 n,内存管理表的每一个项对应内存池的一块内存。 内存管理表的项值代表的意义为:当该项值为 0 的时候,代表对应的内存块未被占用,当该项值非零的时候,代表该项对应的内存块已经被占用,其数值则代表被连续占用的内存块数。 比如某项值为 10,那么说明包括本项对应的内存块在内,总共分配了 10 个内存块给外部的某个指针。
分配原理
当指针 p 调用 malloc 申请内存的时候,先判断 p 要分配的内存块数(m),然后从第 n 项开始,向下查找,直到找到 m 块连续的空内存块(即对应内存管理表项为 0),然后将这 m 个内 存管理表项的值都设置为 m(标记被占用),最后,把最后的这个空内存块的地址返回指针 p, 完成一次分配。注意,如果当内存不够的时候(找到最后也没找到连续的 m 块空闲内存),则返回 NULL 给 p,表示分配失败。
释放原理
当 p 申请的内存用完,需要释放的时候,调用 free 函数实现。free 函数先判断 p 指向的内 存地址所对应的内存块,然后找到对应的内存管理表项目,得到 p 所占用的内存块数目 m(内 存管理表项目的值就是所分配内存块的数目),将这 m 个内存管理表项目的值都清零,标记释放,完成一次内存释放。
说明
本文章的内存管理设计思想完全参考了正点原子的资料,设计方法基本一致,唯一不同的是后续提供的实现源码是本人根据上述设计思路实现的,没有使用正点原子的代码,可移植到任何平台使用,特此说明。
二.源码
源码在windows平台编译测试过,功能完全ok。
#include<stdio.h>
#include <string.h>
#define MAX_LEN 1024*10 //内存池大小
#define BLOCK_SIZE 128 //内存块大小
unsigned char mem_buff[MAX_LEN] = {0};
typedef struct
{
unsigned char index[MAX_LEN/BLOCK_SIZE];
}_mem_tab;
_mem_tab mem_tab;
unsigned char *my_malloc(int buf_size)
{
int i = 0;
int j = 0;
int flag = 0;
int record = 0; //记录当前分配内存管理表项的位置
int block_num = 0; //需要分配内存块的数量
block_num = buf_size%BLOCK_SIZE ? buf_size/BLOCK_SIZE+1 : buf_size/BLOCK_SIZE;
printf("block_num: %d \r\n",block_num);
if(block_num > MAX_LEN/BLOCK_SIZE){//申请内存大小超出内存池范围,退出
return NULL;
}
while(i < MAX_LEN/BLOCK_SIZE){
if(mem_tab.index[i] == 0){
if(flag == 0){
flag = 1;
record = i;
}
j++;
if(j >= block_num){
memset(mem_tab.index+record,block_num,block_num);
return (mem_buff+record*BLOCK_SIZE);
}
}else{
flag = 0;
j = 0;
}
i++;
}
return NULL;
}
void my_free(unsigned char *buf)
{
int num = 0;
if(buf == NULL){
printf("NULL buffer!!!\r\n");
return;
}
//判断释放的缓存地址是否在内存池范围内
if(*(&buf) < *(&mem_buff) || *(&buf) > *(&mem_buff) + MAX_LEN){
printf("error buffer!!!\r\n");
return;
}
num = (*(&buf) - *(&mem_buff))/BLOCK_SIZE;
/*
printf("buff addr %d\r\n",*(&buf));
printf("buff addr %d\r\n",*(&mem_buff));
printf("size %d \r\n",*(&buf) - *(&mem_buff));
printf("num %d \r\n",mem_tab.index[num]);
*/
//清除管理表项标记
memset(mem_tab.index+num,0,mem_tab.index[num]);
//清除回收回来的内存池内容
memset(buf,0,num*BLOCK_SIZE);
//将内存指针指向空
buf = NULL;
}
void main(void)
{
unsigned char test[] = "this is a test project !";
unsigned char *buf;
buf = my_malloc(sizeof(test));
if(buf != NULL){
memcpy(buf,test,sizeof(test));
printf("%s",buf);
my_free(buf);
}
}