欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

STM32工作笔记0071---内存管理实验

程序员文章站 2022-07-03 11:00:34
...

技术交流QQ群【JAVA,C++,Python,.NET,BigData,AI】:170933152

STM32工作笔记0071---内存管理实验

STM32工作笔记0071---内存管理实验

STM32工作笔记0071---内存管理实验

战舰版参考这个

然后:探索版也是这个

STM32工作笔记0071---内存管理实验

mini版参考下面这个

STM32工作笔记0071---内存管理实验

STM32工作笔记0071---内存管理实验

STM32工作笔记0071---内存管理实验

 STM32工作笔记0071---内存管理实验

STM32工作笔记0071---内存管理实验

如果咱们用传统的方法,不用内存管理的话,如果要再LCD上,显示文件名的话,就需要建立一个上面说道的

这个数组,二维数组,比如有10000个文件,然后每个文件有255个长度的名称.这里就需要创建上面的那个大的数组

就需要2550k字节的内存,这个对MCU来说是压力很大的.

STM32工作笔记0071---内存管理实验

STM32工作笔记0071---内存管理实验

如果,再小一点,就是如果你有100个文件,每个文件有100个长度的文件名,这样就可以小一点了,

但是,你不知道,有可能有些文件的文件名只要一个两个字符,你还是要给他分配100个长度这样

就太浪费了,这就是不用内存管理的坏处.

如果用内存管理就可以做到,针对每个文件用多少内存就分配多少内存,这样

会更好一些.

STM32工作笔记0071---内存管理实验

有了内存管理以后,就可以针对,文件名的长度,来动态的给每个文件分配内存,也可以根据文件的个数来动态分配内存,

用完了以后,还可以释放内存,如果没有内存管理,可能要针对所有可能的情况去申请内存,这样

对内存是非常浪费的.

STM32工作笔记0071---内存管理实验

然后再看看内存管理的方法

STM32工作笔记0071---内存管理实验

这个分块式内存管理模块,也就是把内存分为很多个内存池,每个内存池由很多个内存块组成,

每个内存块,对应第一个内存管理表,当对应的内存管理表,中值是0的时候,也就是这个对应的内存块,可以使用,如果

内存块,的值不是0,比如说是10的时候,那么相邻的连续的比如说,有3个连续的内存管理表

的值都是10,那么也就是说,这3个内存管理表,对应的3个内存块就分配给了外部的某个指针了.

STM32工作笔记0071---内存管理实验

当内存管理刚初始化的时候,会清空所有的内存块,对应的内存管理表的值,都是清空成0,代表

所有的内存块都是可以被使用的,然后,要注意,这里查找某个内存块能不能使用,是从顶到低的方式来查询的.

STM32工作笔记0071---内存管理实验

malloc的内存分配原理:
说起来就是需要分配的时候,会先计算一下,比如我申请100字节的内容,那么,如果一个内存块是32个字节,那么就需要

4个内存块,那么这个时候,malloc就会从顶到底去查找,找到连续4个内存管理表是0的,也就是没有被占用的内存块

然后把,这4个连续的是0的内存管理表,标记为4,因为这里需要4个内存块,然后返回这4个空内存块的地址,

如果找到了低还是找不到连续的4个,没有被占用的内存块的话,那么就返回一个null,表示分配失败了.

STM32工作笔记0071---内存管理实验

然后看这个内存释放原理.

当调用free的时候,,首先找到需要的内存块的内存地址,找到地址后,找到内存管理表,根据内存管理表,得到占用的内存块

数目比如是m,然后把m个内存管理表,的值都清零,这样完成内存释放.

STM32工作笔记0071---内存管理实验

STM32工作笔记0071---内存管理实验

STM32工作笔记0071---内存管理实验

STM32工作笔记0071---内存管理实验

这里这个SRAMBANK这个是针对开发版不一样,这个值也不一样的,

比如战舰版,因为有2个外置SRAM一个内置的所以就是3,mini版只有内置的SRAM所以就是1

然后这个init这个函数,这参数的作用就是,如果传入的是1的话,那么就是使用第一个SRAM,如果

传入的是2的话,就是使用第二个SRAM.

然后这

STM32工作笔记0071---内存管理实验

STM32工作笔记0071---内存管理实验

STM32工作笔记0071---内存管理实验

可以看到上面右边就是mini版的,他的init和perused,以及下面的结构体都是只有一个的,也就是因为他没有外置的sram.

STM32工作笔记0071---内存管理实验

这里的内存表大小就是指的是,内存管理表的个数,也就是有多少个内存块

STM32工作笔记0071---内存管理实验

这里因为内存管理表用来存一些数据,而且内存管理表还对应内存块,

所以管理所有MEM_MAX_SIZE的内存,需要再MEM_MAX_SIZE内存大小的基础上+MEM_ALLOC_TABLE_SIZE *2 的这么多字节

STM32工作笔记0071---内存管理实验

STM32工作笔记0071---内存管理实验

STM32工作笔记0071---内存管理实验

STM32工作笔记0071---内存管理实验

STM32工作笔记0071---内存管理实验

STM32工作笔记0071---内存管理实验

STM32工作笔记0071---内存管理实验

这里的字节对齐,是什么意思,后边有文章会说.

这里可以这样理解这个字节对齐的意思,

比如STM32,32位的是4个字节

那么4字节对齐就是说

如果我使用,小于等于32位的空间的时候,实际上都会给分配32位的空间

STM32工作笔记0071---内存管理实验

perused这个是内存使用率

STM32工作笔记0071---内存管理实验

可以看到战舰版的内存初始化函数

这里的所属内存块,就是,比如是内置的SRAM,还是外置的SRAM等等.

STM32工作笔记0071---内存管理实验

mini版的内存初始化函数.

可以看到mini版的内存初始化函数中没有传入对应的是哪个内存池.

STM32工作笔记0071---内存管理实验

可以看看,战舰版的内存使用率的使用方法,可以看到他就是找到所有不是0的内存管理表

也就是所有已经使用的管理表,然后去除以,这个sram的总的内存表大小.

然后*100,就得到了这个内存使用率.

STM32工作笔记0071---内存管理实验

这个是mini版的,内存使用率方法,可以看到参数是void.

然后再去看申请内存的方法:

STM32工作笔记0071---内存管理实验

可以看到,返回的是申请的内存首地址,如果没有申请到内存返回NULL

STM32工作笔记0071---内存管理实验

可以看到这里,返回值是,如果不是0XFFFF FFFF ,就说明申请地址成功,那么

就是内存的偏移地址,

这个偏移地址:

STM32工作笔记0071---内存管理实验

就是地址的偏移量.

//内存分配(内部调用)
//memx:所属内存块
//size:要分配的内存大小(字节)
//返回值:0XFFFFFFFF,代表错误;其他,内存偏移地址 
//1.分配内存用的函数
u32 my_mem_malloc(u8 memx,u32 size)  
{  
    signed long offset=0;  
    u32 nmemb;	//需要的内存块数  
	u32 cmemb=0;//连续空内存块数
    u32 i;  
    //2.先去判断内存有没有被初始化,没有的话,就去先初始化
    if(!mallco_dev.memrdy[memx])mallco_dev.init(memx);//未初始化,先执行初始化 
    //3.如果前来申请的内存大小是0的话,就是不需要分配内存,直接就返回0XFFFF FFFF
    if(size==0)return 0XFFFFFFFF;//不需要分配
    //4.否则先去找到,内存的块数,也就是
    //要申请的字节数 / 一个块的最小字节大小 也就是算出来,用几个内存块
    //
    nmemb=size/memblksize[memx];  	//获取需要分配的连续内存块数
    //5.如果算出来要用的内存块,有余数,那么
    //内存块数需要++
    //
    if(size%memblksize[memx])nmemb++;  
    //6.然后再去所有的内存控制区域中去查找,连续的
    //可以使用的内存块数.
    //这里的控制区域指的是,memtblsize,这是拥有的所有的内存块数
    for(offset=memtblsize[memx]-1;offset>=0;offset--)//搜索整个内存控制区  
    {     
        //7.如果找到对应的内存模块,
        //他的第offset个内存表,是0的话,那么就cmemb++
        //如果中间不连续的话,那么cmemb就需要重新开始计数
        //
		if(!mallco_dev.memmap[memx][offset])cmemb++;//连续空内存块数增加
		else cmemb=0;								//连续内存块清零

        //8.如果连续找到了够用的内存块,那么就
		if(cmemb==nmemb)							//找到了连续nmemb个空内存块
		{
            //9.给找到的内存块做上标记,
            //也就是给对应的内存管理表都赋值上需要的内存块数
            //比如申请100个字节的话,一个内存块是32字节的话
            //那么就需要4个内存块,这里就给找到的连续的内存管理表
            //上面都赋值上4
            for(i=0;i<nmemb;i++)  					//标注内存块非空 
            {  
                mallco_dev.memmap[memx][offset+i]=nmemb;  
            }  
            //10.然后返回找到的内存的偏移地址
            //找到的第几个内存块*每个内存块的大小,
            //比如找到第3个内存块了,每个内存块的大小是32
            //那么地址应该是3*32
            return (offset*memblksize[memx]);//返回偏移地址  
		}
    }  
    return 0XFFFFFFFF;//未找到符合分配条件的内存块  
} 

STM32工作笔记0071---内存管理实验

然后看这里就是,返回对应的,分配的内存的地址,

这里:

//分配内存(外部调用)
//memx:所属内存块
//size:内存大小(字节)
//返回值:分配到的内存首地址.
void *mymalloc(u8 memx,u32 size)  
{  
    u32 offset;   
    //1.返回找到的连续的内存块的地址偏移量
	offset=my_mem_malloc(memx,size);  	   	 	   
    if(offset==0XFFFFFFFF)return NULL; 
    //2.基地址,也就是对应的那个SRAM模块的基地址,加上偏移量
    //得到的就是一个完整的分配的内存地址了 
    else return (void*)((u32)mallco_dev.membase[memx]+offset);  
}  

STM32工作笔记0071---内存管理实验

然后再看一下,这里myfree这个函数.

这个函数用来释放内存的.

//释放内存(外部调用) 
//memx:所属内存块
//ptr:内存首地址 
void myfree(u8 memx,void *ptr)  
{  
	u32 offset;   
    //1.第一个参数是,那个SRAM模块设备
    //第二个参数是,要释放的内存地址
    //2.如果传入的要释放的内存地址是个NULL那么就返回就行了
	if(ptr==NULL)return;//地址为0.  
    //3.否者就先找到这个要释放的地址的
    //偏移量,然后,调用my_mem_free,去释放内存
 	offset=(u32)ptr-(u32)mallco_dev.membase[memx];     
    my_mem_free(memx,offset);	//释放内存      
}  

STM32工作笔记0071---内存管理实验

然后看看内存释放这个函数的具体过程:

//释放内存(内部调用) 
//memx:所属内存块
//offset:内存地址偏移
//返回值:0,释放成功;1,释放失败;  
u8 my_mem_free(u8 memx,u32 offset)  
{  
    int i;  
    //1.这个函数也是先判断这个内存能不能用,不能用
    //去初始化内存,然后返回内存释放成功
    if(!mallco_dev.memrdy[memx])//未初始化,先执行初始化
	{
		mallco_dev.init(memx);    
        return 1;//未初始化  
    }  
    //2.然后再看看,偏移量是不是在
    //内存池里面,这里,如果偏移量在内存池中的话,再去
    //处理,也就是这个偏移,是不是再内存总大小之内
    if(offset<memsize[memx])//偏移在内存池内. 
    {  
        //3.在内存总大小之内的话,就先找到
        //这块内存要在第几个内存块中,也就是所在的内存块的号码
        int index=offset/memblksize[memx];			//偏移所在内存块号码  
        //4.找到在第几个内存块以后,
        //然后再在这个内存块,对应的内存管理表中,去找到,这个内存占用了
        //几个内存块.
        int nmemb=mallco_dev.memmap[memx][index];	//内存块数量
        for(i=0;i<nmemb;i++)  						//内存块清零
        {  
            //5.然后从开始位置,把这个占用的这几个内存块
            //对应的内存管理表的值都设置为0
            mallco_dev.memmap[memx][index+i]=0;  
        }  
        return 0;  
    }else return 2;//偏移超区了.  
}  

这里的释放内存实际上就是,把对应的内存管理表给清零就可以了.

STM32工作笔记0071---内存管理实验

STM32工作笔记0071---内存管理实验

然后看看:

STM32工作笔记0071---内存管理实验

#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "lcd.h"
#include "usart.h"	  
#include "sram.h"
#include "string.h"
#include "usmart.h"	
#include "malloc.h"
 
/************************************************
 ALIENTEK精英STM32开发板实验34
 内存管理 实验 
 技术支持:www.openedv.com
 淘宝店铺:http://eboard.taobao.com 
 关注微信公众平台微信号:"正点原子",免费获取STM32资料。
 广州市星翼电子科技有限公司  
 作者:正点原子 @ALIENTEK
************************************************/

 
 int main(void)
 {	 
	u8 key;		 
 	u8 i=0;	    
	u8 *p=0;
	u8 *tp=0;
	u8 paddr[18];				//存放P Addr:+p地址的ASCII值
  
   //1.首先做一些初始化
	delay_init();	    	 //延时函数初始化	  
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
	uart_init(115200);	 	//串口初始化为115200
 	LED_Init();		  			//初始化与LED连接的硬件接口
	KEY_Init();					//初始化按键
	LCD_Init();			   		//初始化LCD   
 	//2.然后初始化内存池,这个内存池就是一个个的内存模块设备
    //一个个的SRAM设备
    my_mem_init(SRAMIN);		//初始化内部内存池 
    //3.然后再LCD显示一些提示
	POINT_COLOR=RED;			//设置字体为红色 
	LCD_ShowString(30,50,200,16,16,"ELITE STM32F103 ^_^");	
	LCD_ShowString(30,70,200,16,16,"MALLOC TEST");	
	LCD_ShowString(30,90,200,16,16,"aaa@qq.com");
	LCD_ShowString(30,110,200,16,16,"2015/1/20"); 
	LCD_ShowString(30,130,200,16,16,"KEY0:Malloc  KEY1:Free");
	LCD_ShowString(30,150,200,16,16,"KEY_UP:Write");

 	POINT_COLOR=BLUE;//设置字体为蓝色 
	LCD_ShowString(30,170,200,16,16,"SRAMIN");
	LCD_ShowString(30,190,200,16,16,"SRAMIN USED:   %");  
  	while(1)
	{	
		key=KEY_Scan(0);			//不支持连按	
		switch(key)
		{
			case 0:					//没有按键按下	
				break;
			case KEY0_PRES:			//KEY0按下
                //3.这里去申请2k的字节,然后
                //往这个地址,去写入Memory Malloc 这样的一串内容
				p=mymalloc(SRAMIN,2048);//申请2K字节
				if(p!=NULL)sprintf((char*)p,"Memory Malloc Test%03d",i);//向p写入一些内容
				break;
			case KEY1_PRES:			//KEY1按下
                //5.按下这个KEY1就会去释放内存
                //SRAMIN,这个是第几个内存池,也就是第几个内存设备
				myfree(SRAMIN,p);	//释放内存
				p=0;				//指向空地址	  
				break;
			case WKUP_PRES:			//KEY UP按下 
				if(p!=NULL)
				{
                    //4.按下WKUP按键的时候,去更新显示内容,然后把内容再显示出来.
					sprintf((char*)p,"Memory Malloc Test%03d",i);//更新显示内容 	 
					LCD_ShowString(30,250,200,16,16,p);			 //显示P的内容
				} 
				break; 
		}
		if(tp!=p)
		{
            //5.然后这个tp是用来判断p这个地址,有没有发生变化的
            //如果发生了变化的话,那么
            //就重新显示一下p的地址.显示在lcd上
            //如果p正常就显示p对应的内容,如果不正常
            //就清除显示.
            //
			tp=p;
			sprintf((char*)paddr,"P Addr:0X%08X",(u32)tp);
			LCD_ShowString(30,230,200,16,16,paddr);	//显示p的地址
			if(p)LCD_ShowString(30,250,200,16,16,p);//显示P的内容
		    else LCD_Fill(30,250,239,266,WHITE);	//p=0,清除显示
		}
		delay_ms(10);   
		i++;
		if((i%20)==0)//DS0闪烁.
		{ 
			LCD_ShowNum(30+96,190,my_mem_perused(SRAMIN),3,16);//显示内部内存使用率
 			LED0=!LED0;
 		}
	}	   
}

然后去测试一下

STM32工作笔记0071---内存管理实验

STM32工作笔记0071---内存管理实验.

STM32工作笔记0071---内存管理实验

STM32工作笔记0071---内存管理实验

STM32工作笔记0071---内存管理实验

STM32工作笔记0071---内存管理实验

要注意使用完内存,一定要及时的进行释放,否则,可能会造成,没有内存可用.

 

相关标签: 硬件嵌入式