datasheet

STM32学习笔记一一内存管理

2019-01-09来源: eefocus 关键字:STM32  内存管理

1.简介


内存管理:指软件运行时对计算机内存资源的分配和使用的技术。其最主要的目的是如何高效,快速的分配,并且在适当的时候释放和回收内存资源。 内存管理的实现方法有很多种,最终都是要实现两个函数: malloc 和 free。


malloc :函数用于内存申请; 

free: 函数用于内存释放。


1.1 分块式内存管理原理


由上图可知,分块式内存管理由内存池和内存管理表两部分组成。内存池被等分为 n块,对应的内存管理表,大小也为 n,内存管理表的每一个项对应内存池的一块内存。


内存管理表的项值代表的意义:当该项值为 0 的时候,代表对应的内存块未被占用;当该项值非零的时候,代表该项对应的内存块已经被占用,其数值则代表被连续占用的内存块数。


比如:某项值为 10,那么说明包括本项对应的内存块在内,总共分配了 10 个内存块给外部的某个指针。内寸分配方向如图所示,是从顶—>底的分配方向。即首先从最末端开始找空内存。当内存管理刚初始化的时候,内存表全部清零,表示没有任何内存块被占用。


1.2 分配原理

当指针 p 调用 malloc 申请内存的时候,先判断 p 要分配的内存块数(m),然后从第 n 项开始,向下查找,直到找到 m 块连续的空内存块(即对应内存管理表项为 0),然后将这 m 个内存管理表项的值都设置为 m(标记被占用),最后,把最后的这个空内存块的地址返回指针 p,完成一次分配。


注:如果当内存不够的时候(找到最后也没找到连续的 m 块空闲内存),则返回 NULL 给 p,表示分配失败。


1.2 释放原理

当 p 申请的内存用完,需要释放的时候,调用 free 函数实现。 free 函数先判断 p 指向的内存地址所对应的内存块,然后找到对应的内存管理表项目,得到 p 所占用的内存块数目 m(内存管理表项目的值就是所分配内存块的数目),将这 m 个内存管理表项目的值都清零,标记释放,完成一次内存释放。


2.软件分析

头文件:


#ifndef __MALLOC_H

#define __MALLOC_H

#include "stm32f10x.h"


#ifndef NULL

#define NULL 0

#endif


//内存参数设定.

#define MEM_BLOCK_SIZE          32                              //内存块大小为32字节

#define MEM_MAX_SIZE            42*1024                         //最大管理内存 42K

#define MEM_ALLOC_TABLE_SIZE    MEM_MAX_SIZE/MEM_BLOCK_SIZE     //内存表大小



//内存管理控制器

struct _m_mallco_dev

{

    void (*init)(void);             //初始化

    u8 (*perused)(void);            //内存使用率

    u8  *membase;                   //内存池 

    u16 *memmap;                    //内存管理状态表

    u8  memrdy;                     //内存管理是否就绪

};

extern struct _m_mallco_dev mallco_dev; //在mallco.c里面定义


void mymemset(void *s,u8 c,u32 count);  //设置内存

void mymemcpy(void *des,void *src,u32 n);//复制内存     

void mem_init(void);                     //内存管理初始化函数(外/内部调用)

u32 mem_malloc(u32 size);               //内存分配(内部调用)

u8 mem_free(u32 offset);                //内存释放(内部调用)

u8 mem_perused(void);                   //得内存使用率(外/内部调用) 

////////////////////////////////////////////////////////////////////////////////

//用户调用函数

void myfree(void *ptr);                 //内存释放(外部调用)

void *mymalloc(u32 size);               //内存分配(外部调用)

void *myrealloc(void *ptr,u32 size);    //重新分配内存(外部调用)

#endif



参考例程:


#include "malloc.h"     


//内存池(4字节对齐)

__align(4) u8 membase[MEM_MAX_SIZE];            //SRAM内存池

//内存管理表

u16 memmapbase[MEM_ALLOC_TABLE_SIZE];           //SRAM内存池MAP

//内存管理参数       

const u32 memtblsize=MEM_ALLOC_TABLE_SIZE;      //内存表大小

const u32 memblksize=MEM_BLOCK_SIZE;            //内存分块大小

const u32 memsize=MEM_MAX_SIZE;                 //内存总大小



//内存管理控制器

struct _m_mallco_dev mallco_dev=

{

    mem_init,           //内存初始化

    mem_perused,        //内存使用率

    membase,            //内存池

    memmapbase,         //内存管理状态表

    0,                  //内存管理未就绪

};


//复制内存

//*des:目的地址

//*src:源地址

//n:需要复制的内存长度(字节为单位)

void mymemcpy(void *des,void *src,u32 n)  

{  

    u8 *xdes=des;

    u8 *xsrc=src; 

    while(n--)

        *xdes++=*xsrc++;  

}  

//设置内存

//*s:内存首地址

//c :要设置的值

//count:需要设置的内存大小(字节为单位)

void mymemset(void *s,u8 c,u32 count)  

{  

    u8 *xs = s;  

    while(count--)

        *xs++=c;  

}      

//内存管理初始化  

void mem_init(void)  

{  

    mymemset(mallco_dev.memmap, 0,memtblsize*2);//内存状态表数据清零  

    mymemset(mallco_dev.membase, 0,memsize);    //内存池所有数据清零  

    mallco_dev.memrdy=1;                        //内存管理初始化OK  

}  

//获取内存使用率

//返回值:使用率(0~100)

u8 mem_perused(void)  

{  

    u32 used=0;  

    u32 i;  


    for(i=0;i

    {  

        if(mallco_dev.memmap[i])

            used++; 

    } 

    return (used*100)/(memtblsize);  

}  

//内存分配(内部调用)

//memx:所属内存块

//size:要分配的内存大小(字节)

//返回值:0XFFFFFFFF,代表错误;其他,内存偏移地址 

u32 mem_malloc(u32 size)  

{  

    signed long offset=0;  

    u16 nmemb;  //需要的内存块数  

    u16 cmemb=0;//连续空内存块数

    u32 i;  


    if(!mallco_dev.memrdy)

        mallco_dev.init();  //未初始化,先执行初始化 

    if(size==0)

        return 0XFFFFFFFF;              //不需要分配

    nmemb=size/memblksize;                      //获取需要分配的连续内存块数

    if(size%memblksize)

        nmemb++;  

    for(offset=memtblsize-1;offset>=0;offset--) //搜索整个内存控制区  

    {     

        if(!mallco_dev.memmap[offset])

            cmemb++;    //连续空内存块数增加

        else 

            cmemb=0;                            //连续内存块清零

        if(cmemb==nmemb)                        //找到了连续nmemb个空内存块

        {

            for(i=0;i

            {  

                mallco_dev.memmap[offset+i]=nmemb;  

            }  

            return (offset*memblksize);         //返回偏移地址  

        }

    }  

    return 0XFFFFFFFF;//未找到符合分配条件的内存块  

}  

//释放内存(内部调用) 

//offset:内存地址偏移

//返回值:0,释放成功;1,释放失败;  

u8 mem_free(u32 offset)  

{  

    int i;  

    if(!mallco_dev.memrdy)//未初始化,先执行初始化

    {

        mallco_dev.init();    

        return 1;//未初始化  

    }  

    if(offset

    {  

int index=offset/memblksize; //偏移所在内存块

[1] [2]

关键字:STM32  内存管理

编辑:什么鱼 引用地址:http://www.eeworld.com.cn/mcu/2019/ic-news010942852.html
本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:STM32学习笔记一一UCOSII(1)
下一篇:STM32学习笔记一一DMA传输

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

STM32:STM32库函数配置

stm32 固件库V3.0以上的版本,main等源文件中不再直接包含stm32f10x_conf.h,而是stm32f10x.h,stm32f10x.h则定义了启动设置,以及所有寄存器宏定义,此文件中需要注意的有:使用V3.0以上版本固件库的方法如下:1.选择device(配置函数STM32F10x.h,具体配置方法如下)在STM32F10x.h中有如下代码:#if !defined (STM32F10X_LD) && !defined (STM32F10X_LD_VL) && !defined (STM32F10X_MD) && !defined
发表于 2019-01-17
STM32:STM32库函数配置

STM32:STM32学习记录1:MDK基本数据类型及代码优化

大概一年前开始接触STM32,当时就被它的库函数开发所吸引,但是迫于各种压力放弃了学习,一直在使用所谓稳定的单片机来开发(忍不住要吐槽),现在终于有时间了,开始自己的兴趣之旅喽!!现在网上有各种大牛的经验文档使我受益匪浅,也感谢室友的无私帮助!!!大概看了一下大牛的经验文档,好像没有一个提到MDK的基本数据类型的,自己找找看在MDK的帮助里面有。打开MDK-----help----uVision help----RealView Compiler Reference Guide----C and C++ implementation details----C and C++ implementation
发表于 2019-01-17
STM32:STM32学习记录1:MDK基本数据类型及代码优化

STM32:STM32学习记录5: 外部中断

配置流程:1:系统时钟初始化,包括系统时钟和要开放的IO口或者功能的时钟配置。2:IO口初始化,包括引脚,速率,输入输出模式等。3:NVIC 中断向量配置 ,中断向量基地址和优先级的配置。4:EXTI 中断/事件控制器,使能或失能外部线路,使能的模式(事件请求和中断请求),边沿触发模式,状态等。说明:1:主函数写在main.c中,中断函数写在stm32f10x_it.c 中,找到相应的中断函数(一般都是空白),加入自己的中断代码即可。2:中断函数名在startup_stm32f10x_xx.s中查阅3:清除 EXT13 线路的挂起位  注意此处一定要清除!!!!!!!!在EXTI_PR寄存器中3:NVIC一般配
发表于 2019-01-17

STM32学习记录——printf函数重定位

功能: 重定位printf函数,使printf作为串口打印输出函数。代替usart_send_string()函数步骤: usart.c中包含USART初始化函数 1、USART初始化(使能时钟、使能GPIO、GPIO和USART初始化) 2、打开USART 3、在usart.c中加入如下代码#ifdef __GNUC__     /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf      
发表于 2019-01-17

STM32USART串口调节与printf重定义

首先,printf重定义后可以直接使用printf函数从串口发送数据在usart.c中添加代码:#ifdef __GNUC__  /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf     set to 'Yes') calls __io_putchar() */  #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)#else  #define PUTCHAR_PROTOTYPE int f
发表于 2019-01-17

STM32中使用标准库重定义printf()函数

//重定义函数1PUTCHAR_PROTOTYPE{ /* Place your implementation of fputc here */ /* e.g. write a character to the USART */  USART_SendData(USART1, (uint8_t) ch);   /* 循环等待直到发送结束*/  while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)  {}   return ch;}//重定义函数2 int fputc
发表于 2019-01-17

小广播

何立民专栏

单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2018 EEWORLD.com.cn, Inc. All rights reserved