STM32-内存管理

#ifndef __MALLOC_H
#define __MALLOC_H
#include "stm32f10x.h"
//////////////////////////////////////////////////////////////////////////////////
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK战舰STM32开发板V3
//内存管理 驱动代码
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2015/1/20
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2009-2019
//All rights reserved
//////////////////////////////////////////////////////////////////////////////////

#ifndef NULL
#define NULL 0
#endif

//定义两个内存池
#define SRAMIN     0        //内部内存池
#define SRAMEX   1        //外部内存池 

#define SRAMBANK     2    //定义支持的SRAM块数.    

//mem1内存参数设定.mem1完全处于内部SRAM里面.
#define MEM1_BLOCK_SIZE            32                                //内存块大小为32字节
#define MEM1_MAX_SIZE            35*1024                          //最大管理内存 40K
#define MEM1_ALLOC_TABLE_SIZE    MEM1_MAX_SIZE/MEM1_BLOCK_SIZE     //内存表大小

//mem2内存参数设定.mem2的内存池处于外部SRAM里面
#define MEM2_BLOCK_SIZE            32                                //内存块大小为32字节
#define MEM2_MAX_SIZE            800 *1024                          //最大管理内存960K
#define MEM2_ALLOC_TABLE_SIZE    MEM2_MAX_SIZE/MEM2_BLOCK_SIZE     //内存表大小 

//内存管理控制器
struct _m_mallco_dev
{
    void (*init)(u8);                    //初始化
    u8 (*perused)(u8);                      //内存使用率
    u8     *membase[SRAMBANK];                //内存池 管理SRAMBANK个区域的内存
    u16 *memmap[SRAMBANK];                 //内存管理状态表
    u8  memrdy[SRAMBANK];                 //内存管理是否就绪
};
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 my_mem_init(u8 memx);                //内存管理初始化函数(外/内部调用)
u32 my_mem_malloc(u8 memx,u32 size);    //内存分配(内部调用)
u8 my_mem_free(u8 memx,u32 offset);        //内存释放(内部调用)
u8 my_mem_perused(u8 memx);                //获得内存使用率(外/内部调用)
////////////////////////////////////////////////////////////////////////////////
//用户调用函数
void myfree(u8 memx,void *ptr);              //内存释放(外部调用)
void *mymalloc(u8 memx,u32 size);            //内存分配(外部调用)
void *myrealloc(u8 memx,void *ptr,u32 size);//重新分配内存(外部调用)
#endif
#include "malloc.h"
//////////////////////////////////////////////////////////////////////////////////
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK战舰STM32开发板V3
//内存管理 驱动代码
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2015/1/20
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2009-2019
//All rights reserved
//////////////////////////////////////////////////////////////////////////////////

//内存池(32字节对齐)
__align(32) u8 mem1base[MEM1_MAX_SIZE];                                                    //内部SRAM内存池
__align(32) u8 mem2base[MEM2_MAX_SIZE] __attribute__((at(0X68000000)));                    //外部SRAM内存池
//内存管理表
u16 mem1mapbase[MEM1_ALLOC_TABLE_SIZE];                                                    //内部SRAM内存池MAP
u16 mem2mapbase[MEM2_ALLOC_TABLE_SIZE] __attribute__((at(0X68000000+MEM2_MAX_SIZE)));    //外部SRAM内存池MAP
//内存管理参数
const u32 memtblsize[SRAMBANK]={MEM1_ALLOC_TABLE_SIZE,MEM2_ALLOC_TABLE_SIZE};            //内存表大小
const u32 memblksize[SRAMBANK]={MEM1_BLOCK_SIZE,MEM2_BLOCK_SIZE};                        //内存分块大小
const u32 memsize[SRAMBANK]={MEM1_MAX_SIZE,MEM2_MAX_SIZE};                                //内存总大小

//内存管理控制器
struct _m_mallco_dev mallco_dev=
{
    my_mem_init,                //内存初始化
    my_mem_perused,                //内存使用率
    mem1base,mem2base,            //内存池
    mem1mapbase,mem2mapbase,    //内存管理状态表
    0,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;
}
//内存管理初始化
//memx:所属内存块
void my_mem_init(u8 memx)
{
    mymemset(mallco_dev.memmap[memx], 0,memtblsize[memx]*2);//内存状态表数据清零
    mymemset(mallco_dev.membase[memx], 0,memsize[memx]);    //内存池所有数据清零
    mallco_dev.memrdy[memx]=1;                                //内存管理初始化OK
}
//获取内存使用率
//memx:所属内存块
//返回值:使用率(0~100)
u8 my_mem_perused(u8 memx)
{
    u32 used=0;
    u32 i;
    for(i=0;i<memtblsize[memx];i++)
    {
        if(mallco_dev.memmap[memx][i])used++;
    }
    return (used*100)/(memtblsize[memx]);
}
//内存分配(内部调用)
//memx:所属内存块
//size:要分配的内存大小(字节)
//返回值:0XFFFFFFFF,代表错误;其他,内存偏移地址
u32 my_mem_malloc(u8 memx,u32 size)
{
    signed long offset=0;
    u32 nmemb;    //需要的内存块数
    u32 cmemb=0;//连续空内存块数
    u32 i;
    if(!mallco_dev.memrdy[memx])mallco_dev.init(memx);//未初始化,先执行初始化
    if(size==0)return 0XFFFFFFFF;//不需要分配
    nmemb=size/memblksize[memx];      //获取需要分配的连续内存块数
    if(size%memblksize[memx])nmemb++;
    for(offset=memtblsize[memx]-1;offset>=0;offset--)//搜索整个内存控制区
    {
        if(!mallco_dev.memmap[memx][offset])cmemb++;//连续空内存块数增加
        else cmemb=0;                                //连续内存块清零
        if(cmemb==nmemb)                            //找到了连续nmemb个空内存块
        {
            for(i=0;i<nmemb;i++)                      //标注内存块非空
            {
                mallco_dev.memmap[memx][offset+i]=nmemb;
            }
            return (offset*memblksize[memx]);//返回偏移地址
        }
    }
    return 0XFFFFFFFF;//未找到符合分配条件的内存块
}
//释放内存(内部调用)
//memx:所属内存块
//offset:内存地址偏移
//返回值:0,释放成功;1,释放失败;
u8 my_mem_free(u8 memx,u32 offset)
{
    int i;
    if(!mallco_dev.memrdy[memx])//未初始化,先执行初始化
    {
        mallco_dev.init(memx);
        return 1;//未初始化
    }
    if(offset<memsize[memx])//偏移在内存池内.
    {
        int index=offset/memblksize[memx];            //偏移所在内存块号码
        int nmemb=mallco_dev.memmap[memx][index];    //内存块数量
        for(i=0;i<nmemb;i++)                          //内存块清零
        {
            mallco_dev.memmap[memx][index+i]=0;
        }
        return 0;
    }else return 2;//偏移超区了.
}
//释放内存(外部调用)
//memx:所属内存块
//ptr:内存首地址
void myfree(u8 memx,void *ptr)
{
    u32 offset;
    if(ptr==NULL)return;//地址为0.
     offset=(u32)ptr-(u32)mallco_dev.membase[memx];
    my_mem_free(memx,offset);    //释放内存
}
//分配内存(外部调用)
//memx:所属内存块
//size:内存大小(字节)
//返回值:分配到的内存首地址.
void *mymalloc(u8 memx,u32 size)
{
    u32 offset;
    offset=my_mem_malloc(memx,size);
    if(offset==0XFFFFFFFF)return NULL;
    else return (void*)((u32)mallco_dev.membase[memx]+offset);
}
//重新分配内存(外部调用)
//memx:所属内存块
//*ptr:旧内存首地址
//size:要分配的内存大小(字节)
//返回值:新分配到的内存首地址.
void *myrealloc(u8 memx,void *ptr,u32 size)
{
    u32 offset;
    offset=my_mem_malloc(memx,size);
    if(offset==0XFFFFFFFF)return NULL;
    else
    {
        mymemcpy((void*)((u32)mallco_dev.membase[memx]+offset),ptr,size);    //拷贝旧内存内容到新内存
        myfree(memx,ptr);                                                        //释放旧内存
        return (void*)((u32)mallco_dev.membase[memx]+offset);                  //返回新内存首地址
    }
}

1. 思想:将内存池分为块,首先定义每个块的字节数,和内存池的总字节数,用总字节数除以每个块的字节数得到块数

2. 内存池,实际上就是一个数组

3. 内存管理块,实际也是一个数组,总元素个数为内存块数,每个元素对应一个内存块,该元素非零时表示该内存块没有被占用

4. 将第一步中的信息用数组保存起来,方便后面的函数调用

5. 将内存抽象为一个结构体,传入的参数分别是,初始化函数,占用率函数,两个内存池(数组)的基地址,两个内存管理状态表(两个u16数组),两个内存池的就绪布尔值

6. 初始化函数,实际上就是将指定内存池(数组)内面的内容全部用0填充,将内存状态表(u16数组)全部用0填充,然后将该内存池的就绪布尔变量置一

7. 计算内存使用率,注意:得到的是块使用的比率,而不是字节使用的比率

8. 复制,就是按字节依次赋值内容

9. 从起始位置将连续count个字节的区域用c填充

10. 分配内存(内部调用),成功:返回相对于数组首地址的偏移地址。

  ->判断指定的内存池是否已经初始化

  ->若传入参数为0,表示不需要分配,直接返回

  ->通过所需字节数对每个块的字节数分别取整,取余得到所需的连续块数

  ->从最后一个块往前面寻找所需的连续块,例如所需的块为3,当找到连续2块而,下一块已经被使用时,则将已经找的的连续块数清零,再在前面找连续的3块

  ->返回的偏移地址为所需连续块的起始块相对于内存池的偏移地址

  ->将即将用到的内存块对应的内存管理表中的元素置为所需的连续块数

11. 分配内存,首先判断偏移地址是否正确,然后返回连续块的首地址

12. 扩大分配内存,首先分配一个指定的内存,再将旧内存里面的内容拷贝到新内存(这里感觉战舰的源码有问题,旧的内存里面原来没有size个元素,却拷贝size个元素到新的空间),

  最后释放旧的内存空间,返回新的内存(块)首地址

13. 清除连续的内存块,成功:返回0

  ->首先通过偏移地址除以每个块的字节数,得到起始块的序号

  ->读取起始块对应的内存控制表元素,得到从起始块开始共要清除多少个连续的块

  ->所谓的清除,实际上只是将对应的内存控制表的元素清零,内存中的值未清零。

  ->为某个对象分配元素时,是分配的连续块,清除时,也是清除这几个连续块,不同对象占用不同的连续块,清除时,不会影响其他对象。

14. 内存释放函数,首先得出偏移地址,然后,调用上一步的函数释放内存

时间: 2024-10-05 05:07:39

STM32-内存管理的相关文章

内存管理(30天自制操作系统--读书笔记)

今天继续读书笔记,“挑战内存管理”(30天自制操作系统). 为什么对这块内容敢兴趣呢,因为曾经遇到这么一个问题.在STM32程序中想使用队列,可不是上篇讲的FIFO,而是使用了较大的内存空间,又想做队列的顺序存取管理. 在这个队列里用到了malloc,动态申请内存,一开始是直接申请不到内存,后来在启动脚本里更改了设置堆的地址值,可以申请成功,但发现申请几次后,也申请不到内存. 果然MCU级别的程序,内存这块处理起来就没有windows程序那么随心所欲了.讲了这么多,开始正题吧. 1.相关数据结构

一个简单而强大的单片机内存管理器-不带内存碎片整理

单片机简单内存管理器 本代码基于无操作系统的STM32单片机开发,功能强大,可申请到地址空间连续的不同大小的内存空间,且用户接口简单,使用方便 转载请注明出处:http://blog.csdn.net/u011833609/article/details/46834203 memory.h #ifndef __MEMORY_H__ #define __MEMORY_H__ #include "stdio.h" #include "string.h" #include

FreeRTOS 动态内存管理

本章节为大家讲解 FreeRTOS 动态内存管理,动态内存管理是 FreeRTOS 非常重要的一项功能,前面章节讲解的任务创建. 信号量. 消息队列. 事件标志组. 互斥信号量. 软件定时器组等需要的 RAM 空间都是通过动态内存管理从 FreeRTOSConfig.h 文件定义的 heap 空间中申请的. 动态内存管理介绍FreeRTOS 支持 5 种动态内存管理方案,分别通过文件 heap_1,heap_2,heap_3,heap_4 和 heap_5实现,这 5 个文件在 FreeRTOS

cortex_m3_stm32嵌入式学习笔记(二十四):内存管理实验(动态内存)

有用过C语言编程的童鞋对动态管理内存肯定有点了解..好处就不多说了 今天实现STM32的动态内存管理 内存管理,是指软件运行时对计算机内存资源的分配和使用的技术.其最主要的目的是如何高效,快速的分配,并且在适当的时候释放和回收内存资源. 内存管理的实现方法有很多种,他们其实最终都是要实现两个函数:malloc 和 free(好熟悉): malloc 函数用于内存申请, free 函数用于内存释放. 实现方式:分块式内存管理 从上图可以看出,分块式内存管理由内存池和内存管理表两部分组成.内存池被等

linux内存管理

一.Linux 进程在内存中的数据结构 一个可执行程序在存储(没有调入内存)时分为代码段,数据段,未初始化数据段三部分:    1) 代码段:存放CPU执行的机器指令.通常代码区是共享的,即其它执行程序可调用它.假如机器中有数个进程运行相同的一个程序,那么它们就可以使用同一个代码段.     2) 数据段:存放已初始化的全局变量.静态变量(包括全局和局部的).常量.static全局变量和static函数只能在当前文件中被调用.     3) 未初始化数据区(uninitializeddata s

Block内存管理实例分析

在ios开发中,相信说道block大家都不陌生,内存管理问题也是开发者最头疼的问题,网上很多讲block的博客,但大都是理论性多点,今天结合一些实例来讲解下. 存储域 首先和大家聊聊block的存储域,根据block在内存中的位置,block被分为三种类型: NSGlobalBlock NSStackBlock NSMallocBlock 从字面意思上大家也可以看出来 NSGlobalBlock是位于全局区的block,它是设置在程序的数据区域(.data区)中. NSStackBlock是位于

Obstack是C标准库里面对内存管理的GNU扩展

Obstack介绍 Obstack初始化 在Obstack中申请对象 释放对象 申请growing object 获取Obstack状态 数据对齐 以下是来自wiki对obstack的介绍: Obstack是C标准库里面对内存管理的GNU扩展(实际上就是GNU C library了).Obstack===Object stack.没错,Obstack就是一个栈,栈里面的元素是对象object(不是面向对象的对象哦,这里的对象单指数据元素).这些数据是动态的,也就是使用的是动态内存.这种内存管理技

OC内存管理

OC内存管理 一.基本原理 (一)为什么要进行内存管理. 由于移动设备的内存极其有限,所以每个APP所占的内存也是有限制的,当app所占用的内存较多时,系统就会发出内存警告,这时需要回收一些不需要再继续使用的内存空间,比如回收一些不再使用的对象和变量等. 管理范围:任何继承NSObject的对象,对其他的基本数据类型无效. 本质原因是因为对象和其他数据类型在系统中的存储空间不一样,其它局部变量主要存放于栈中,而对象存储于堆中,当代码块结束时这个代码块中涉及的所有局部变量会被回收,指向对象的指针也

39-oc集合中对象的内存管理

集合中对象的内存管理 集合的内存管理原则是什么 当把一个对象添加到集合中时,这个对象会做了一次retain操作,计数器会+1 当一个集合被销毁时,会对集合里面的所有对象做一次release操作,计数器会-1 当一个对象从集合中移除时,会对这个对象做一次release操作,计数器会-1 集合方法的普遍规律是什么 如果方法名是add\insert开头,那么被添加的对象,计数器会+1 如果方法名是remove\delete开头,那么被移除的对象,计数器-1

iOS基础 ----- 内存管理

Objective-C 的内存管理方式有引用计数机制,垃圾回收机制,自动释放池.有alloc,就有释放.iOS应?程序出现Crash(闪退),90%的原因是因为内存问 题.在?个拥有数?个甚?是上百个类的?程?,查找内存问 题极其困难,学会内存管理,能帮我们减少出错的?率.内存问题体现在两个??:内存溢出.野指针异常. 引用计数器 在Xcode4.2及之后的版本中由于引入了ARC(Automatic Reference Counting)机制,程序编译时Xcode可以自动给你的代码添加内存释放代