1.内存管理介绍

  内存管理,是指软件运行时对计算机内存资源的分配和使用的技术。其最主要的目的是如
何高效,快速的分配,并且在适当的时候释放和回收内存资源。 内存管理的实现方法有很多种,
他们其实最终都是要实现 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 个内存管理表项目的值都清零,标记释
放,完成一次内存释放。

该原理解释要结合下面的内部调用函数理解

2.代码介绍

  该次程序 只实现了内部内存池的内存管理,还有外部内存池(SDRAM) 和CCM 内存池(此部分 SRAM 仅仅 CPU 可以访问)未实现,
但一般程序只要前者就够了。内部内存池是STM32F4内部的处理芯片的RAM,STM32F429 本身自带的 256K 字节内存 ,普通内存

(地址从: 0X2000 0000 开始,共 192KB),这部分内存任何外设都可以访问 

内存管理的宏定义参数:即把160k的内存分为64块,每块大小为2560B

#define MEM1_BLOCK_SIZE            64                              //内存块大小为64字节
#define MEM1_MAX_SIZE 160*1024 //最大管理内存 160K
#define MEM1_ALLOC_TABLE_SIZE MEM1_MAX_SIZE/MEM1_BLOCK_SIZE //内存表大小

管理结构体:因为是静态分配的内存管理,所以用宏定义的结构体,动态分配的能力有限,弄不了。

struct _m_mallco_dev
{
uint8_t *membase; //内存池 管理SRAMBANK个区域的内存
uint32_t *memmap; //内存管理状态表
uint8_t memrdy; //内存管理是否就绪
}; extern struct _m_mallco_dev malloc_handle2;

内存管理函数

extern void malloc_set(void *s,uint8_t c,uint32_t count);       //设置内存(基本函数)
extern void malloc_cpy(void *des,void *src,uint32_t n); //复制内存(基本函数) extern void malloc_Outfree(void *ptr); //内存释放(外部调用)
extern void *malloc_Outallot(uint32_t size); //内存分配(外部调用) //外部调用内部
extern uint32_t malloc_mem(uint32_t size); //内存分配(内部调用)
extern uint8_t malloc_free(uint32_t offset); //内存释放(内部调用) extern uint16_t malloc_perused(void) ; //获得内存使用率(外/内部调用)
extern void malloc_init(void); //内存管理初始化函数(外/内部调用)

malloc.c程序,由原子的内存管理实验原码改制而来,有大幅度变化,只支持内部内存池,最好看看原子的实验原码,会有更深的了解,就不具体讲解了。

/******************************仅用于内部存储模块SRAM*******************************************/
//内存池(32字节对齐)
__align() uint8_t mem1base[MEM1_MAX_SIZE]; //内部SRAM内存池 //内存管理表
__align() uint32_t memmapbase[MEM1_ALLOC_TABLE_SIZE]; //内部SRAM内存池MAP //内存管理参数
const uint32_t memtblsize=MEM1_ALLOC_TABLE_SIZE; //内存表大小
const uint32_t memblksize=MEM1_BLOCK_SIZE; //内存分块大小
const uint32_t memsize=MEM1_MAX_SIZE; //内存总大小 struct _m_mallco_dev malloc_handle2=
{
mem1base,
memmapbase,
,
}; //内存管理初始化
//malloc_handle1内存管理结构体
void malloc_init()
{ malloc_set(malloc_handle2.memmap,,memtblsize*); //内存状态表数据清零
malloc_handle2.memrdy=; //内存管理初始化OK } //获取内存使用率
//malloc_handle1内存管理结构体
//返回值:使用率(扩大了10倍,0~1000,代表0.0%~100.0%)
uint16_t malloc_perused(void)
{
uint32_t used=;
uint32_t i; for(i=;i<memtblsize;i++)
{ if(malloc_handle2.memmap[i])
{
used++; } } printf("%u\n",used);
return (used*)/(memtblsize);
} //复制内存
//*des:目的地址
//*src:源地址
//n:需要复制的内存长度(字节为单位)
void malloc_cpy(void *des,void *src,uint32_t n)
{
uint8_t *xdes=des;
uint8_t *xsrc=src;
while(n--)
*xdes++=*xsrc++;
} //设置内存
//*s:内存首地址
//c :要设置的值
//count:需要设置的内存大小(字节为单位)
void malloc_set(void *s,uint8_t c,uint32_t count)
{
uint8_t *xs = s;
while(count--)
*xs++=c; } //分配内存(外部调用)
//malloc_handle1内存管理结构体
//size:内存大小(字节)
//返回值:分配到的内存首地址.
void *malloc_Outallot(uint32_t size)
{
uint32_t offset; offset=malloc_mem(size); if(offset==0XFFFFFFFF)
return NULL;
else
return (void*)((uint32_t)malloc_handle2.membase+offset); } //释放内存(外部调用)
//malloc_handle1内存管理结构体
//ptr:内存首地址
void malloc_Outfree(void *ptr)
{
uint32_t offset;
if(ptr==NULL)
return; offset=(uint32_t )ptr-(uint32_t )malloc_handle2.membase;
malloc_free(offset); } //内存分配(内部调用)
//malloc_handle1内存管理结构体
//size:要分配的内存大小(字节)
//返回值:0XFFFFFFFF,代表错误;其他,内存偏移地址
uint32_t malloc_mem(uint32_t size)
{
signed long offset=;
uint32_t nmemb; //需要的内存块数
uint32_t cmemb=; //连续空内存块数
uint32_t i;
if(!malloc_handle2.memrdy)
malloc_init(); //未初始化,先执行初始化
if(size==)
return 0XFFFFFFFF; //不需要分配
//malloc_handle1->memmap=mem1mapbase;
nmemb=size/memblksize; //获取需要分配的连续内存块数
if(size%memblksize)
nmemb++;
for(offset=memtblsize-;offset>=;offset--)//搜索整个内存控制区
{
if(!malloc_handle2.memmap[offset])
cmemb++; //连续空内存块数增加
else
cmemb=; //连续内存块清零
if(cmemb==nmemb) //找到了连续nmemb个空内存块
{
for(i=;i<nmemb;i++) //标注内存块非空
{
malloc_handle2.memmap[offset+i]=nmemb;
}
return (offset*memblksize);//返回偏移地址
}
}
return 0XFFFFFFFF;//未找到符合分配条件的内存块
} //释放内存(内部调用)
//malloc_handle1内存管理结构体
//offset:内存地址偏移
//返回值:0,释放成功;1,释放失败;
uint8_t malloc_free(uint32_t offset)
{
int i;
int index=offset/memblksize; //偏移所在内存块号码
int nmemb=malloc_handle2.memmap[index]; //内存块数量
if(!malloc_handle2.memrdy)//未初始化,先执行初始化
{
malloc_init(); ;
return ; //未初始化
}
if(offset<=memsize) //偏移在内存池内.
{ for(i=;i<nmemb;i++) //内存块清零
{
malloc_handle2.memmap[index+i]=NULL;
}
return ;
}
else
return ;//偏移超区了.
}

3.测试

测试代码

  


uint8_t paddr[20]; //存放P Addr:+p地址的ASCII值
uint16_t memused=0;
uint8_t key;
uint8_t *p=0;
uint8_t i=0;


key=KEY_Scan();            //按键扫描
switch(key)
{
case WKUP_PRES:
{
//printf("aa");
p=malloc_Outallot();//申请2K字节
if(p!=NULL)
sprintf((char*)p,"AAAAAAAA",i);//向p写入一些内容
printf("写入:%s", p);
memused=malloc_perused();
sprintf((char*)paddr,"%d.%01d%%",memused/,memused%);
printf("%s",paddr); break;
} case KEY2_PRES:
{
malloc_Outfree(p);//释放内存
printf("释放:%s", p);
p=; //指向空地址
memused=malloc_perused();
sprintf((char*)paddr,"%d.%01d%%",memused/,memused%);
printf("%s",paddr);
break;
}
case KEY1_PRES:
{ break;
}
case KEY0_PRES:
{ break;
}
}

测试结果

4,注意事项

申请的内存使用完后,一定要释放掉,不然内存池会被写爆。

有不足之处请指正,谢谢阅读,麻烦点赞支持。

基于STM32F429的内存管理的更多相关文章

  1. ML2021 | (腾讯)PatrickStar:通过基于块的内存管理实现预训练模型的并行训练

    ​  前言  目前比较常见的并行训练是数据并行,这是基于模型能够在一个GPU上存储的前提,而当这个前提无法满足时,则需要将模型放在多个GPU上.现有的一些模型并行方案仍存在许多问题,本文提出了一种名为 ...

  2. 基于Redis做内存管理

    1 Redis存储机制: redis存储的数据类型包括,String,Hash,List,Set,Sorted Set,它内部使用一个redisObject对象来表示所有的key和value,这个对象 ...

  3. 为什么说Python采用的是基于值的内存管理模式?

    Python中的变量并不直接存储值,而是存储了值的内存地址或者引用,假如为不同变量赋值为相同值,这个值在内存中只有一份,多个变量指向同一块内存地址.

  4. 内存管理内幕mallco及free函数实现

    原文:https://www.ibm.com/developerworks/cn/linux/l-memory/ 为什么必须管理内存 内存管理是计算机编程最为基本的领域之一.在很多脚本语言中,您不必担 ...

  5. <转载>内存管理内幕-动态分配的选择、折衷和实现 对malloc内存分配有个简单的描述,对内存管理有个大致的说明

    这篇文章看后感觉不错,和我在glibc下的hurdmalloc.c文件里关于malloc的实现基本意思相同,同时,这篇文章还介绍了一些内存管理方面的知识,值得推荐. 原文链接地址为:http://ww ...

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

    Obstack是C标准库里面对内存管理的GNU扩展 Obstack介绍 Obstack初始化 在Obstack中申请对象 释放对象 申请growing object 获取Obstack状态 数据对齐 ...

  7. 伙伴系统之伙伴系统概述--Linux内存管理(十五)

    在内核初始化完成之后, 内存管理的责任就由伙伴系统来承担. 伙伴系统基于一种相对简单然而令人吃惊的强大算法. Linux内核使用二进制伙伴算法来管理和分配物理内存页面, 该算法由Knowlton设计, ...

  8. Linux内核入门到放弃-内存管理-《深入Linux内核架构》笔记

    概述 内存管理的实现涵盖了许多领域: 内存中的物理内存页管理 分配大块内存的伙伴系统 分配较小内存块的slab.slub和slob分配器 分配非连续内存块的vmalloc机制 进程的地址空间 在IA- ...

  9. 自动内存管理算法 —— 标记和复制法

    最近阅读了<垃圾回收算法手册>这本经典的书籍,借此机会打算写几篇内存管理算法方面的文章,也算是自己的总结吧.                                         ...

随机推荐

  1. CodeForces - 556C Case of Matryoshkas (水题)

    Andrewid the Android is a galaxy-famous detective. He is now investigating the case of vandalism at ...

  2. VS2019 开发Django(八)------视图

    导航:VS2019开发Django系列 这几天学习了一下Django的视图和模板,从这几天的学习进度来看,视图这里并没有花很多的时间,相反的,模板花费了大量的时间,主要原因还是因为对Jquery操作d ...

  3. 【CV现状-3.2】纹理与材质

    #磨染的初心--计算机视觉的现状 [这一系列文章是关于计算机视觉的反思,希望能引起一些人的共鸣.可以随意传播,随意喷.所涉及的内容过多,将按如下内容划分章节.已经完成的会逐渐加上链接.] 缘起 三维感 ...

  4. 6. abp中的拦截器

    abp拦截器基本定义 拦截器接口定义: public interface IAbpInterceptor { void Intercept(IAbpMethodInvocation invocatio ...

  5. SVN中怎样忽略当前文件不提交

    场景 在使用SVN进行版本管理时,有时一些自动生成的文件比如证书等,在每台电脑上都会不同,如果将其提交,则会冲突. 怎样将指定的文件或者指定文件后缀的文件忽略提交. 注: 博客主页: https:// ...

  6. 使用GDAL/OGR读写矢量文件

    感觉GIS中矢量相关内容还是挺庞杂的,并且由于版本迭代的关系,使用GDAL/OGR读写矢量的资料也有点不太一样.这里总结了一个读写矢量的示例,实现代码如下: #include <iostream ...

  7. Hadoop_简介_01

    1. Apache Hadoop 1.1 Hadoop介绍 Hadoop是Apache旗下的一个用java语言实现的开源软件框架, 是一个开发和运行处理大规模数据的软件平台. 允许使用简单的编程模型在 ...

  8. Linux Pptpd

    准备环境 1 主机ip:192.168.0.107 2 VPN服务器: ens32:192.168.0.102 ens33:127.16.1.10 软件安装 [root@localhost ~]# y ...

  9. Netty如何监控内存泄露

    目录 Netty如何监控内存泄露 前言 JDK的弱引用和引用队列 Netty的实现思路 代码实现 分配监控对象 追踪和检查泄露 Netty如何监控内存泄露 前言 一般而言,在Netty程序中都会采用池 ...

  10. vue学习笔记(十)路由

    前言 在上一篇博客vue学习笔记(九)vue-cli中的组件通信内容中,我们学习组件通信的相关内容和进行了一些组件通信的小练习,相信大家已经掌握了vue-cli中的组件通信,而本篇博客将会带你更上一层 ...