内存管理的实现方法有很多种,其实最终都是要实现两个函数:malloc 和 free。malloc 函数用来内存申请,free 函数用于内存释放。本文通过分块式内存管理的方式实现:
只不过代码中分配方向为1->n
没有使用正点原子的代码,而是自己封装实现了,方便添加多个内存进行管理
/**********************************************************************
*file:内存管理文件
*author:残梦
*versions:V1.0
*date:2023.10.23
*note:注:本内存管理采用分块式方式
内存块0 内存块1 内存块2 … 内存块n
内存表0 内存表1 内存表2 … 内存表3
分配方向:0->n
内存表采用4字节uint32_t定义,单次分配字节数不可大于此0xFFFFFFFF
内存管理自身消耗内存=单个内存表4字节 * 内存块数 + sizeof(memory_manage_StructDef) + 地址对齐损失字节数
更多可以参考正点原子的内存分配,本文件思路采用正点原子,但是更推荐使用FreeRTOS的heap4思路
使用方式:
1、添加内存枚举及名称:MemoryList_EnumDef 和 Name_MemoryList
2、分配内存大小及内存数组:dMemory0_Size 和 memory0_heap[dMemory0_Size]
3、调用memory_init()初始化内存管理(可以修改单个内存块字节大小,dAlign_Byte的整数倍)
4、可以开始使用memory_malloc()、memory_realloc()、memory_free()
5、内存剩余百分比:memory_SurplusRatio()
注:使用内存分配memory_malloc()\memory_realloc()后,不使用此资源后需使用memory_free()释放内存,避免内存泄露|不够
**********************************************************************/
memory_driver.h
#ifndef _memory_driver_H_
#define _memory_driver_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stdint.h"
//内存0--参数
#define dMemory0_Size ((uint32_t )(5*1024)) //分配内存大小
typedef enum
{
eMemory_SRAM_Inside = 0,//内部SRAM
eMemory_Number//内存数
}MemoryList_EnumDef;//内存类别
int32_t memory_init(void);
void *memory_malloc(MemoryList_EnumDef memory,uint32_t size);
void memory_free(MemoryList_EnumDef memory,void *ptr);
void *memory_realloc(MemoryList_EnumDef memory,void *ptr,uint32_t size);
float memory_SurplusRatio(MemoryList_EnumDef memory);
void memory_test(void);
#ifdef __cplusplus
}
#endif
#endif
memory_driver.c
/**********************************************************************
*file:内存管理文件
*author:残梦
*versions:V1.0
*date:2023.10.23
*note:注:本内存管理采用分块式方式
内存块0 内存块1 内存块2 ...... 内存块n
内存表0 内存表1 内存表2 ...... 内存表3
分配方向:0->n
内存表采用4字节uint32_t定义,单次分配字节数不可大于此0xFFFFFFFF
内存管理自身消耗内存=单个内存表4字节 * 内存块数 + sizeof(memory_manage_StructDef) + 地址对齐损失字节数
更多可以参考正点原子的内存分配,本文件思路采用正点原子,但是更推荐使用FreeRTOS的heap4思路
使用方式:
1、添加内存枚举及名称:MemoryList_EnumDef 和 Name_MemoryList
2、分配内存大小及内存数组:dMemory0_Size 和 memory0_heap[dMemory0_Size]
3、调用memory_init()初始化内存管理(可以修改单个内存块字节大小,dAlign_Byte的整数倍)
4、可以开始使用memory_malloc()、memory_realloc()、memory_free()
5、内存剩余百分比:memory_SurplusRatio()
注:使用内存分配memory_malloc()\memory_realloc()后,不使用此资源后需使用memory_free()释放内存,避免内存泄露|不够
**********************************************************************/
#include "memory_driver.h"
#include "stdio.h"
#define dDebug_Printf //开启调试打印信息
//格式参数
#define dAlign_Byte (4) //对齐字节数
#define dAlign_Mask (dAlign_Byte - 1) //对齐掩码
typedef struct
{
uint32_t block;//内存块总数
uint32_t address;//内存池起始地址
uint32_t size_block;//内存块大小,dAlign_Byte的整数倍;单位-字节
uint32_t *table;//内存池管理表:0--未使用,!0--连续占用内存块
//统计使用资源
uint32_t block_surplus;//剩余内存块
}memory_manage_StructDef;//内存堆具体分配参数
static const char Name_MemoryList[eMemory_Number][12] = {"SRAM_Inside"};
static memory_manage_StructDef *memory_manage[eMemory_Number];
//需要自己定义的内存池数组
static uint8_t memory_status[eMemory_Number] = {0};//内存可用状态,0--未初始化;1--已初始化
static uint8_t memory0_heap[dMemory0_Size] = {0};//内存0数组;使用其他内存时,可以指定数组地址位置,如:uint32_t pbuffer[(32*1024*1024)/4] __attribute__((at(0xC0000000)));//0xC0000000是SDRAM1的起始地址
static int32_t memory_init_assign(MemoryList_EnumDef type,uint32_t StartAddress,uint32_t size_total,uint32_t size_block);
/****************************************
@function:内存管理初始化指定SRAM
@param: type--内存类型
StartAddress--内存起始地址
size_total--内存大小,不得低于1KB;单位-字节
size_block--内存块大小,dAlign_Byte的整数倍,且不低于dAlign_Byte * 8;单位-字节
@return:0--初始化成功,!0初始化失败
@note:
-1--参数错误
****************************************/
static int32_t memory_init_assign(MemoryList_EnumDef type,uint32_t StartAddress,uint32_t size_total,uint32_t size_block)
{
uint32_t address = 0;
uint32_t xTotalHeapSize = 0;
uint32_t block = 0,block_self = 0,x = 0;
int64_t i = 0;
if((type >= eMemory_Number)\
|| (size_total < 1024)\
|| (size_block < (dAlign_Byte * 8))\
|| (size_block % dAlign_Byte))return -1;
//对地址进行对齐;地址对齐后:起始地址address,可用内存大小:xTotalHeapSize
address = StartAddress;
xTotalHeapSize = size_total;
if((address & dAlign_Mask) != 0)
{
address += dAlign_Mask;
address &= ~((uint32_t ) dAlign_Mask);
xTotalHeapSize -= (address - StartAddress);
}
//划分内存块 内存块数=block,起始地址=address
block = xTotalHeapSize / size_block;
//分配所需消耗资源,内存表
x = sizeof(memory_manage_StructDef ) + block*4;//内存表内存块大小=4字节
block_self = x / size_block;
if(x % size_block)block_self++;
memory_manage[type] = (memory_manage_StructDef *)address;
memory_manage[type]->block = block;
memory_manage[type]->address = address;
memory_manage[type]->size_block = size_block;
memory_manage[type]->table = (uint32_t *)(address + sizeof(memory_manage_StructDef ));
memory_manage[type]->block_surplus = block;
//内存管理表设置:分配方向0->n
for(i=0;i < memory_manage[type]->block;i++)
{
if(i < block_self)//内存管理资源占用
{
memory_manage[type]->table[i] = block_self;
memory_manage[type]->block_surplus--;
}
else {memory_manage[type]->table[i] = 0;}//内存管理表清零
}
memory_status[type] = 1;
#ifdef dDebug_Printf
printf("内存类别:%s\t内存总大小:%.3f%s\n内存起始地址:0x%0x\t内存块大小:%dbyte\n内存块起始地址:0x%0x\t内存块总数:%d\n可用内存块数:%d\n",\
Name_MemoryList[type],\
((size_total < 1024)?((float)size_total):((size_total < 1024*1024)?((float)size_total/1024.0f):((float)size_total/1024.0f/1024.0f))),\
((size_total < 1024)?"Byte":((size_total < 1024*1024)?"KB":"MB")),\
StartAddress,memory_manage[type]->size_block,\
memory_manage[type]->address,memory_manage[type]->block,memory_manage[type]->block_surplus);
#endif
return 0;
}
/****************************************
@function:内存管理初始化
@param:void
@return:-1--失败,0--成功
@note:
****************************************/
int32_t memory_init(void)
{
if(memory_init_assign(eMemory_SRAM_Inside,(uint32_t )memory0_heap,dMemory0_Size,64) < 0){printf("Error memory_init:%s initialization failed...\n",Name_MemoryList[eMemory_SRAM_Inside]);return -1;}
return 0;
}
/****************************************
@function:分配所需的内存空间,并返回一个指向它的指针
@param: memory--待分配内存源
size--分配内存大小,单位字节
@return:函数返回一个指针 ,指向已分配大小的内存。如果请求失败,则返回 NULL。
@note:
****************************************/
void *memory_malloc(MemoryList_EnumDef memory,uint32_t size)
{
uint8_t flag = 0;
uint32_t block = 0,cnt = 0,address = 0,offset = 0;
int64_t i = 0;
if((memory >= eMemory_Number)\
|| (memory_manage[memory]->block_surplus == 0)\
|| (size == 0)\
|| (memory_status[memory] == 0))
{return NULL;}
//计算所需内存块数
block = size / memory_manage[memory]->size_block;
if(size % memory_manage[memory]->size_block)block++;
if(block > memory_manage[memory]->block)return NULL;
//寻找可用的内存块
for(i= 0,flag = 0,cnt = 0;i < memory_manage[memory]->block;i++)
{
if(memory_manage[memory]->table[i]){cnt = 0;}
else
{
cnt++;
if(cnt >= block){flag = 1;break;}
}
}
if(!flag)return NULL;//内存不足
offset = i - block + 1;//已经寻找到足够的内存块,内存块起始点=offset,块数block
//标记内存块
for(i=offset;i < (offset + block);i++)
{
memory_manage[memory]->table[i] = block;
memory_manage[memory]->block_surplus--;
}
address = memory_manage[memory]->address + offset * memory_manage[memory]->size_block;//分配内存的起始地址
return (void *)address;
}
/****************************************
@function:释放之前调用 memory_malloc 或 memory_realloc 所分配的内存空间
@param: memory--待分配内存源
ptr--指针指向一个要释放内存的内存块,该内存块之前是通过调用memory_malloc 或 memory_realloc进行分配内存的。如果传递的参数是一个空指针,则不会执行任何动作。
@return:void
@note:
****************************************/
void memory_free(MemoryList_EnumDef memory,void *ptr)
{
uint32_t address = 0,offset = 0,i = 0,cnt = 0;
if((memory >= eMemory_Number)\
|| (ptr == NULL)\
|| (memory_status[memory] == 0))
{return;}
address = (uint32_t )ptr;//获取地址
offset = (address - memory_manage[memory]->address) / memory_manage[memory]->size_block;
cnt = memory_manage[memory]->table[offset];
for(i = 0;i < cnt;i++)
{
memory_manage[memory]->table[offset + i] = 0;
memory_manage[memory]->block_surplus++;
}
ptr = NULL;
}
/****************************************
@function:重新调整之前调用 malloc 或 calloc 所分配的 ptr 所指向的内存块的大小
@param: memory--待分配内存源
ptr--指针指向一个要重新分配内存的内存块,该内存块之前是通过调用 memory_malloc、memory_realloc进行分配内存的。如果为空指针,则会分配一个新的内存块,且函数返回一个指向它的指针。
size--内存块的新的大小,以字节为单位。如果大小为 0,且 ptr 指向一个已存在的内存块,则 ptr 所指向的内存块会被释放,并返回一个空指针。
@return:函数返回一个指针 ,指向已分配大小的内存。如果请求失败,则返回 NULL。
@note:
****************************************/
void *memory_realloc(MemoryList_EnumDef memory,void *ptr,uint32_t size)
{
void *p = NULL;
uint32_t *address = NULL,*address_last = NULL;
uint32_t size_last = 0,i = 0;
if((memory >= eMemory_Number)\
|| (size == 0)\
|| (memory_status[memory] == 0))
{return NULL;}
if(ptr == NULL)return memory_malloc(memory,size);//ptr未分配过内存
size_last = memory_manage[memory]->table[((uint32_t )ptr - memory_manage[memory]->address)/memory_manage[memory]->size_block] * memory_manage[memory]->size_block;
if(size_last > size)return NULL;//之前分配的内存比当前需求大
//分配新的内存
p = memory_malloc(memory,size);
if(p == NULL)return NULL;
//拷贝之前的数据至新的位置
address = (uint32_t *)p;
address_last = (uint32_t *)ptr;
for(i = 0;i < size_last/4;i++){address[i] = address_last[i];}
memory_free(memory,ptr);
return p;
}
/****************************************
@function:内存可用空间百分比
@param: memory--待分配内存源
@return:void
@note:注:未包括地址对齐损失字节
****************************************/
float memory_SurplusRatio(MemoryList_EnumDef memory)
{
if((memory >= eMemory_Number) || (memory_status[memory] == 0))return 0.0f;
return ((float )memory_manage[memory]->block_surplus / (float )memory_manage[memory]->block * 100.0f);
}
/****************************************
@function:内存管理测试函数
@param:void
@return:void
@note:打印的err = 0表示正确
nblock:%d / %d为剩余内存块/总内存块数
****************************************/
void memory_test(void)
{
uint32_t *size = NULL;
uint32_t err = 0,i = 0;
printf("nblock:%d / %d\n",memory_manage[eMemory_SRAM_Inside]->block_surplus,memory_manage[eMemory_SRAM_Inside]->block);
size = (uint32_t *)memory_malloc(eMemory_SRAM_Inside,64*32);
printf("nblock:%d / %d\n",memory_manage[eMemory_SRAM_Inside]->block_surplus,memory_manage[eMemory_SRAM_Inside]->block);
for(i = 0;i < 64*32/4;i++) *(size + i) = i;
size = memory_realloc(eMemory_SRAM_Inside,(void *)size,64*40);
printf("nblock:%d / %d\n",memory_manage[eMemory_SRAM_Inside]->block_surplus,memory_manage[eMemory_SRAM_Inside]->block);
for(i = 0;i < 64*32/4;i++) if(*(size + i) != i) err++;
printf("err=%d\n",err);
memory_free(eMemory_SRAM_Inside,size);
printf("nblock:%d / %d\n",memory_manage[eMemory_SRAM_Inside]->block_surplus,memory_manage[eMemory_SRAM_Inside]->block);
float *pfloat = NULL;
pfloat = (float *)memory_malloc(eMemory_SRAM_Inside,4*64);
for(i = 0;i < 64;i++) *(pfloat + i) = i*10.0f;
printf("float nblock:%d / %d\n",memory_manage[eMemory_SRAM_Inside]->block_surplus,memory_manage[eMemory_SRAM_Inside]->block);
pfloat = memory_realloc(eMemory_SRAM_Inside,(void *)pfloat,4*64*2);
for(i = 0,err = 0;i < 64;i++) if((uint32_t)pfloat[i] != i*10)err++;
printf("float err=%d\n",err);
memory_free(eMemory_SRAM_Inside,pfloat);
printf("float nblock:%d / %d\n",memory_manage[eMemory_SRAM_Inside]->block_surplus,memory_manage[eMemory_SRAM_Inside]->block);
uint8_t *pu8 = NULL;
pu8 = (uint8_t *)memory_malloc(eMemory_SRAM_Inside,4*64);
for(i = 0;i < 4*64;i++) *(pu8 + i) = i;
printf("uint8_t nblock:%d / %d\n",memory_manage[eMemory_SRAM_Inside]->block_surplus,memory_manage[eMemory_SRAM_Inside]->block);
pu8 = (uint8_t *)memory_realloc(eMemory_SRAM_Inside,(void *)pu8,4*64*2);
for(i = 0,err = 0;i < 4*64;i++) if((uint32_t)pu8[i] != i)err++;
printf("uint8_t err=%d\n",err);
memory_free(eMemory_SRAM_Inside,pu8);
printf("uint8_t nblock:%d / %d\n",memory_manage[eMemory_SRAM_Inside]->block_surplus,memory_manage[eMemory_SRAM_Inside]->block);
while(1);
}
源码文件下载:
链接:https://pan.baidu.com/s/1iT5s587Rl1wtSdtHCPPwrw
提取码:diep