LV16-28-Memory-01-内存管理基础

本文主要是STM32开发——内存管理的一些基础知识相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。

点击查看使用工具及版本
Windows windows11
Ubuntu Ubuntu16.04的64位版本
VMware® Workstation 16 Pro 16.2.3 build-19376536
SecureCRT Version 8.7.2 (x64 build 2214) - 正式版-2020年5月14日
开发板 正点原子 i.MX6ULL Linux阿尔法开发板
uboot NXP官方提供的uboot,NXP提供的版本为uboot-imx-rel_imx_4.1.15_2.1.0_ga(使用的uboot版本为U-Boot 2016.03)
linux内核 linux-4.15(NXP官方提供)
STM32开发板 正点原子战舰V3(STM32F103ZET6)
点击查看本文参考资料
  • 通用
分类 网址说明
官方网站https://www.arm.com/ARM官方网站,在这里我们可以找到Cotex-Mx以及ARMVx的一些文档
https://www.st.com/content/st_com/zh.htmlST官方网站,在这里我们可以找到STM32的相关文档
https://www.stmcu.com.cn/意法半导体ST中文官方网站,在这里我们可以找到STM32的相关中文参考文档
http://elm-chan.org/fsw/ff/00index_e.htmlFatFs文件系统官网
教程书籍《ARM Cortex-M3权威指南》ARM公司专家Joseph Yiu(姚文祥)的力作,中文翻译是NXP的宋岩
《ARM Cortex-M0权威指南》
《ARM Cortex-M3与Cortex-M4权威指南》
开发论坛http://47.111.11.73/forum.php开源电子网,正点原子的资料下载及问题讨论论坛
https://www.firebbs.cn/forum.php国内Kinetis开发板-野火/秉火(刘火良)主持的论坛,现也做STM32和i.MX RT
https://www.amobbs.com/index.php阿莫(莫进明)主持的论坛,号称国内最早最火的电子论坛,以交流Atmel AVR系列单片机起家,现已拓展到嵌入式全平台,其STM32系列帖子有70W+。
http://download.100ask.net/index.html韦东山嵌入式资料中心,有些STM32和linux的相关资料也可以来这里找。
博客参考http://www.openedv.com/开源网-原子哥个人博客
http://blog.chinaaet.com/jihceng0622博主是原Freescale现NXP的现场应用工程师
cortex-m-resources这其实并不算是一个博客,这是ARM公司专家Joseph Yiu收集整理的所有对开发者有用的官方Cortex-M资料链接(也包含极少数外部资源链接)
  • STM32
STM32STM32 HAL库开发实战指南——基于F103系列开发板野火STM32开发教程在线文档
STM32库开发实战指南——基于野火霸道开发板野火STM32开发教程在线文档
  • SD卡
SD Association提供了SD存储卡和SDIO卡系统规范
点击查看相关文件下载
STM32F103xx英文数据手册STM32F103xC/D/E系列的英文数据手册
STM32F103xx中文数据手册STM32F103xC/D/E系列的中文数据手册
STM32F10xxx英文参考手册(RM0008)STM32F10xxx系列的英文参考手册
STM32F10xxx中文参考手册(RM0008)STM32F10xxx系列的中文参考手册
Arm Cortex-M3 处理器技术参考手册-英文版Cortex-M3技术参考手册-英文版
STM32F10xxx Cortex-M3编程手册-英文版(PM0056)STM32F10xxx/20xxx/21xxx/L1xxxx系列Cortex-M3编程手册-英文版
SD卡相关资料——最新版本有关SD卡的一些资料可以从这里下载
SD卡相关资料——历史版本有关SD卡的一些历史版本资料可以从这里下载,比如后边看的SD卡2.0协议
SD 2.0 协议标准完整版这是一篇关于SD卡2.0协议的中文文档,还是比较有参考价值的,可以一看

我们学习了使用 STM32F1 驱动外部 SRAM,以扩展 STM32F1 的内存,加上STM32F1 本身自带的 64K 字节内存,我们可供使用的内存还是比较多的。如果我们所用的内存都像上一节的 testsram 那样,定义一个数组来使用,显然不是一个好办法。后来在使用Flash做Bootloader实验的时候,就无法在原有工程中定义一个55KB的数组,然后 lcd做字模缩放的时候,数组也是预先定义好的,直接就16KB,再加上一些其他的,STM32内部Flash一共就64KB,直接被我占满,sct文件中定义了SRAM的长度,导致编译都无法通过,所以动态的去管理内存就很有必要了。

一、内存管理简介

1. 什么是内存管理

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

2. 两个函数

我们不详细去挖malloc和free是如何申请和释放内存的,这里只学习函数的用法。

2.1 malloc()

1
2
3
4
5
6
7
#include <stdlib.h>
extern _ARMABI void *malloc(size_t /*size*/);
/*
* allocates space for an object whose size is specified by 'size' and whose
* value is indeterminate.
* Returns: either a null pointer or a pointer to the allocated space.
*/

【函数说明】申请指定字节数的内存空间。

【函数参数】

  • size_t :函数的声明中,只有形参类型,我们在keil中追踪这个类型,会发现它其实就是 unsigned int 类型,表示我们要申请的内存空间的字节数。

【注意事项】

(1)申请到的内存空间不会自动初始化,我们需要自己去初始化;

(2)函数返回值为void *类型,我们需要做强制类型转换,转换为我们需要的数据类型的指针类型。

2.2 free()

1
2
3
4
5
6
7
8
9
#include <stdlib.h>
extern _ARMABI void free(void * /*ptr*/);
/*
* causes the space pointed to by ptr to be deallocated (i.e., made
* available for further allocation). If ptr is a null pointer, no action
* occurs. Otherwise, if ptr does not match a pointer earlier returned by
* calloc, malloc or realloc or if the space has been deallocated by a call
* to free or realloc, the behaviour is undefined.
*/

【函数说明】释放通过malloc申请的内存空间。

【函数参数】

  • void :函数的声明中,只有形参类型,这是一个void *类型,表示要释放的内存空间的首地址。

【注意事项】

二、分布式内存管理

我们来学习一种比较简单的办法来实现:分块式内存管理。

1. 基本原理

image-20230515230445906

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

内存管理表的项值代表的意义:当该项值为0的时候,代表对应的内存块未被占用,当该项值非零的时候,代表该项对应的内存块已经被占用,其数值则代表被连续占用的内存块数。比如某项值为10,那么说明包括本项对应的内存块在内,总共分配了10个内存块给外部的某个指针。

内存分配方向:是从顶到底的分配方向。即首先从最末端开始找空内存。当内存管理刚初始化的时候,内存管理表全部清零,表示没有任何内存块被占用。

2. 分配原理

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

3. 释放原理

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

三、函数设计

1. 内存管理控制结构体

1
2
3
4
5
6
7
8
9
// 内存管理控制器
typedef struct __malloc_dev
{
int8_t (*init)(uint8_t); // 初始化
uint8_t (*perused)(uint8_t); // 内存使用率
uint8_t *membase[SRAMBANK]; // 内存池 管理SRAMBANK个区域的内存
uint16_t *memmap[SRAMBANK]; // 内存管理状态表
uint8_t memrdy[SRAMBANK]; // 内存管理是否就绪
}FUNC_MEM;

2. 其他函数

其他的那些函数这里就没必要写了,可以看这里:Hardware/func_mem.c · sumumm/STM32F103-Prj - 码云 - 开源中国 (gitee.com)Hardware/func_mem.h · sumumm/STM32F103-Prj - 码云 - 开源中国 (gitee.com)