RT-Thread内核的我们已经基本都学习过了,除了基本的线程操作和通信,
内核部分还有内存管理和中断处理,本文主要就来说说内存管理相关问题。

目录

  • 前言
  • 一、为什么要内存管理
  • 二、RT-Thread 内存堆管理
    • 2.1 RT-Thread 内存分配
    • 2.2 RT-Thread内存堆管理方式
      • 2.2.1 内存堆管理的3种方式
      • 2.2.2 管理方式的程序配置
    • 2.3 内存堆 API 函数
  • 三、RT-Thread 内存池
    • 3.1 内存池的位置
    • 3.2 内存池程序配置和控制块
    • 3.3 内存池操作 API 函数
  • 结语

前言

记得最初学习 RT-Thread ,对于内存管理我也是简单看看然后一笔带过,当时觉得用不上,在我做的一些传感器单品项目上,对于内存管理确实知道与不知道没什么关系,但是随着认知的增长,项目复杂程度增加,发现内存管理还不可或缺,于是今时今日正好再次来更新 RT-Thread记录,有必要好好的说一说。

RT-Thread 有2种内存管理方式,分别是动态内存堆管理和静态内存池管理。

先不管这两种方式是怎么实现的,首先要明白一个问题,为什么要内存管理?

本 RT-Thread 专栏记录的开发环境:
RT-Thread记录(一、RT-Thread 版本、RT-Thread Studio开发环境 及 配合CubeMX开发快速上手)
RT-Thread记录(二、RT-Thread内核启动流程 — 启动文件和源码分析
RT-Thread 内核篇系列博文链接:
RT-Thread记录(三、RT-Thread 线程操作函数及线程管理与FreeRTOS的比较)
RT-Thread记录(四、RT-Thread 时钟节拍和软件定时器)
RT-Thread记录(五、RT-Thread 临界区保护)
RT-Thread记录(六、IPC机制之信号量、互斥量和事件集)
RT-Thread记录(七、IPC机制之邮箱、消息队列)

一、为什么要内存管理

什么是内存管理?为什么需要内存管理?

在我们的程序设计中,一些数据需要的内存大小需要在程序运行过程中根据实际情况确定,在用户需要一段内存空间时,向系统申请,系统选择一段合适的内存空间分配给用户,用户使用完毕后,再释放回系统,以便系统将该段内存空间回收再利用。

这样子不断的申请释放,如果没有内存管理,就会导致内存碎片,对程序产生极大的影响。

具体的原因我在下面博文有详细说明:

浅谈 malloc 函数在单片机上的应用

如果看完上面的博文,就应该知道了内存管理的重要性。

我们确实直接在函数或者线程里面创建临时变量使用 线程栈 或 者系统栈处理临时变量,但是正如上面博文里面所说的,作为一个通用的操作系统,都会且必须得有自己的合理的内存管理方式。
这个在我们现在说明的 RT-Thread 操作系统上是内核已经实现好的,我们得了解它。

知道了为什么,那么接下来我们就来了解一下 RT-Thread 的这2种内存管理方式。

二、RT-Thread 内存堆管理

现在看看内存堆管理, 所谓堆,看过我博文的朋友应该已经很熟悉了,对于裸机中的堆的位置,大小设定都应该会有一个详细的认知,如果还不知道堆,可以查看下面这篇博文一步到位的理解:

STM32的内存管理相关(内存架构,内存管理,map文件分析)

上文虽然是以STM32为例子说明,但是对于 C/C++ 程序编译后的存储数据段 在不同芯片上的顺序基本都是一样的,于是乎在我的又一篇博文中

嵌入式RTOS的 任务栈 和 系统栈

就得到了一张内存分配的示意图:

2.1 RT-Thread 内存分配

要理解 RT-Thread 内存堆管理,首先得知道它管理的是哪一块内存,所以得知道 RT-Thread 内存分配。

其实细心的朋友会发现,我在博文

RT-Thread记录(二、RT-Thread内核启动流程 — 启动文件和源码分析)

中提到过 RT-Thread 内存分配情况,在其中的 2.2.2 RT-Thread 堆和栈空间说明(与FreeRTOS不同)有过说明:

通过上面的分析,我们可以得到 RT-Thread 下的内存分配的示意图:

通过上面我们自己的分析,再结合官方说明文档的说明,我们应该能完全明白了什么是 RT-Thread 的内存堆:

至此,我们可以确实的明白,RT-Thread 内存管理管理的是哪一部分的内存了。

2.2 RT-Thread内存堆管理方式

那么RT-Thread 对于内存堆,是如何管理的呢?

说明:对于这部分,我个人记录是以知道为主,毕竟我们专栏以应用为主,我们了解会用即可,如果以后确实自己会需要自己写内存管理,肯定会单独更新一篇博文。
我们先前的基础介绍直接使用官网说明,本节后部分会说明下程序中是怎么选择使用的。

2.2.1 内存堆管理的3种方式

RT-Thread 内存堆管理又根据具体内存设备划分为三种情况:

  • 针对小内存块的分配管理(小内存管理算法)
  • 针对大内存块的分配管理(slab 管理算法)
  • 针对多内存堆的分配情况(memheap 管理算法)

这里套用官方的介绍做个简单说明(如果需要深入了解可以去官网查看):

2.2.2 管理方式的程序配置

我们上面 简单介绍了RT-Thread 内存堆管理的3种方式,虽然我们没有详细分析内部是如何实现,那么我们也得了解在 RT-Thread 工程中,是怎么配置使用哪一种管理方式,同时了解这些方式的实现在程序什么文件中。

在工程的rtconfig.h中有关于内存管理方式的配置:

上图是使用小内存堆管理算法。

如果是使用 slab 管理算法,需要宏定义如下:

#define RT_USING_SLAB
#define RT_USING_HEAP

如果是使用 memheap 管理算法,需要宏定义如下:

#define RT_USING_MEMHEAP_AS_HEAP

具体的实现文件是在工程 mem.c 文件中,如下图:

RT-Thread 内存管理详细的实现方式可以自行查看该文件,这里就不过多介绍。

2.3 内存堆 API 函数

对于 RT-Thread 内存堆管理,是有自己的 malloc 函数,不能直接用 c 语言库中原始的malloc 函数。

其 三种管理算法提供的 API 都是相同的。

初始化:

首先是初始化函数:

/*小内存堆和slab 管理算法*/
void rt_system_heap_init(void* begin_addr, void* end_addr);/*memheap 管理算法*/
rt_err_t rt_memheap_init(struct rt_memheap  *memheap,const char  *name,void        *start_addr,rt_uint32_t size)

我在《RT-Thread记录(二、RT-Thread内核启动流程 — 启动文件和源码分析)》板级硬件初始化 — rt_hw_board_init 小结中提到过 这个函数,:

RT-Thread内存堆初始化函数是在系统启动时候初始化的,而不是我们用户在main函数中再初始化的。

内存管理操作函数:

简单记录一下:

/*
分配内存块
参数:
nbytes  需要分配的内存块的大小,单位为字节
返回  ——
分配的内存块地址    成功
RT_NULL     失败
*/
void *rt_malloc(rt_size_t nbytes);
/*
释放内存块
参数:
ptr     待释放的内存块指针
*/
void rt_free (void *ptr);
/*
重分配内存块
参数  描述
rmem    指向已分配的内存块
newsize     重新分配的内存大小
返回  ——
重新分配的内存块地址  成功
*/
void *rt_realloc(void *rmem, rt_size_t newsize);
/*
分配多内存块
参数  描述
count   内存块数量
size    内存块容量
返回  ——
指向第一个内存块地址的指针   成功 ,并且所有分配的内存块都被初始化成零。
RT_NULL     分配失败
*/
void *rt_calloc(rt_size_t count, rt_size_t size);/*
设置内存钩子函数
参数  描述
hook    钩子函数指针
*/
void rt_malloc_sethook(void (*hook)(void *ptr, rt_size_t size));
/*
上面函数的hook 函数接口
参数  描述
ptr     分配到的内存块指针
size    分配到的内存块的大小
*/
void hook(void *ptr, rt_size_t size);/*
释放内存钩子函数
参数  描述
hook    钩子函数指针
*/
void rt_free_sethook(void (*hook)(void *ptr));
/*
上面函数的hook 函数接口
参数  描述
ptr     待释放的内存块指针
*/
void hook(void *ptr);

释放内存块后要清空内存块指针,不然会成为野指针。

三、RT-Thread 内存池

RT-Thread 的第二种内存管理方式是 内存池,内存池是一种内存分配方式,用于分配大量大小相同的小内存块,它可以极大地加快内存分配与释放的速度,且能尽量避免内存碎片化。
他是为了提高内存分配的效率,并且避免内存碎片而产生的。

基本介绍套用官方说明:

内存池属于 内核对象!!支持线程挂起功能。

内核对线什么意思?就是我们前面说到的,线程,IPC机制,这些东西都是内核对象,所以存在 内存池 控制块。

有一个点要注意,内存池申请的内存块大小固定!

3.1 内存池的位置

内存池也是内存管理,那么他创建的之后在内存的什么位置呢?

首先明白内存池作为一个对象,其实可以认为是一个变量,那么他基本上就是属于.bss段的东西了,在RT-Thread 中,他的位置应该是在 .bss段的。

我们按照上面的内存分配的示意图说明一下内存池申请的内存位置:

为了验证一下是否如此,可以初始化一个内存池,编译后查看一下.map文件:

内存池属于.bss段的数据,只不过他一般来说都是申请的相对比较大的一块内存空间,然后在这个大空间内自己有自己的分配管理方式。

3.2 内存池程序配置和控制块

内存池程序配置:

RT-Thread 的内存池在程序中的配置和实现文件如下图:

内存池控制块:(因为是内对象,所以还是熟悉的配方,熟悉的味道~ ~)

struct rt_mempool
{struct rt_object parent;void        *start_address;  /* 内存池数据区域开始地址 */rt_size_t     size;           /* 内存池数据区域大小 */rt_size_t     block_size;    /* 内存块大小  */rt_uint8_t    *block_list;   /* 内存块列表  *//* 内存池数据区域中能够容纳的最大内存块数  */rt_size_t     block_total_count;/* 内存池中空闲的内存块数  */rt_size_t     block_free_count;/* 因为内存块不可用而挂起的线程列表 */rt_list_t     suspend_thread;/* 因为内存块不可用而挂起的线程数 */rt_size_t     suspend_thread_count;
};
typedef struct rt_mempool* rt_mp_t;

内存池具体管理方法的实现可以自己查看下源码,这里暂时不做深入研究。

3.3 内存池操作 API 函数

内存池作为内核对象,那么他的操作就和以前那些IPC机制,线程一样的方式,分为动态创建,静态初始化这些。

并不需要在 板级初始化的时候就初始化。用户可以自己选择用于不用。

简单记录说明一下内存池操作函数:

/*
创建内存池
参数  描述
name    内存池名
block_count     内存块数量
block_size  内存块容量
返回  ——
内存池的句柄  创建内存池对象成功
RT_NULL     创建失败
*/
rt_mp_t rt_mp_create(const char* name,rt_size_t block_count,rt_size_t block_size);
/*
删除内存池
参数  描述
mp  rt_mp_create 返回的内存池对象句柄
返回  ——
RT_EOK  删除成功
*/
rt_err_t rt_mp_delete(rt_mp_t mp);
/*
初始化内存池
参数  描述
mp  内存池对象
name    内存池名
start   内存池的起始位置
size    内存池数据区域大小
block_size  内存块容量
返回  ——
RT_EOK  初始化成功
- RT_ERROR  失败
*/
rt_err_t rt_mp_init(rt_mp_t mp,const char* name,void *start, rt_size_t size,rt_size_t block_size);
/*
脱离内存池
参数  描述
mp  内存池对象
返回  ——
RT_EOK  成功
*/
rt_err_t rt_mp_detach(rt_mp_t mp);
/*
分配内存块
参数  描述
mp  内存池对象
time    超时时间
返回  ——
分配的内存块地址    成功
RT_NULL     失败
*/
void *rt_mp_alloc (rt_mp_t mp, rt_int32_t time);
/*
释放内存块
参数  描述
block   内存块指针
*/
void rt_mp_free (void *block);

结语

本文从为什么要内存管理说起,了解了 RT-Thread 的2种内存管理方式:内存堆 和 内存池。

相信不管你平时用不用动态内存申请,看了这篇文章以后也会对 RT-Thread 的内存管理有一定的了解,在以后需要用到动态内存分配的同时也不会手足无措!

但是特别注意,不管使用哪种方式,在申请的内存使用完之后都必须及时释放,而且要注意清空相应的指针!

但是本文的重点在于理解 为什么要内存管理,和 内存管理管理的是哪一块的内存,对于如何实现内存管理我们只是借用了官方的说明,还是没有深入的研究分析。这个需要等以后博主有机会自己写一套内存管理方式的时候,或许会单独开一篇博文深入分析。

谢谢!

RT-Thread记录(八、理解 RT-Thread 内存管理)相关推荐

  1. C语言文件联系人管理碎片整理,深入理解C语言内存管理.docx

    深入理解C语言内存管理 之前在学Java的时候对于Java虚拟机中的内存分布有一定的了解,但是最近在看一些C,发现居然自己对于C语言的内存分配了解的太少. 问题不能拖,我这就来学习一下吧,争取一次搞定 ...

  2. 深入理解Linux内核---内存管理zone

    转载:https://blog.csdn.net/gatieme/article/details/52384529 https://blog.csdn.net/gatieme/article/deta ...

  3. (转载)深入理解Linux中内存管理---分段与分页简介

    首先,必须要阐述一下这篇文章的主题是Linux内存管理中的分段和分页技术. 来回顾一下历史,在早期的计算机中,程序是直接运行在物理内存上的.换句话说,就是程序在运行的过程中访问的都是物理地址.如果这个 ...

  4. C语言与JAVA内存管理_深入理解C语言内存管理

    之前在学Java的时候对于Java虚拟机中的内存分布有一定的了解,但是最近在看一些C,发现居然自己对于C语言的内存分配了解的太少. 问题不能拖,我这就来学习一下吧,争取一次搞定. 在任何程序设计环境及 ...

  5. Java基础知识(八) Java平台与内存管理

    Java基础知识 1. 为什么说Java是平台独立性语言 2. Java 平台与此他语言平台有哪些区别 3. JVM 加载 class 文件的原理机制是什么 4. 什么是GC 5. Java 是否存在 ...

  6. 深入理解Linux内核-内存管理

    页框管理 内核对整个物理内存进行分页,每页大小为4KB或者4MB(大小无所谓,不同os都可能不一样),一般认为Linux的页大小为4KB,内核必须记录好每个页框的信息,所以linux内核把所有的页框都 ...

  7. memcached全面剖析–2.理解memcached的内存存储

    版权声明:可以任意转载,但转载时必须标明原作者charlee.原始链接http://tech.idv2.com/2008/07/11/memcached-002/以及本声明 下面是<memcac ...

  8. memcached完全剖析系列教程《转》 memcached完全剖析系列教程–2.理解memcached的内存存储...

    本文目录 Slab Allocation机制:整理内存以便重复使用 · Slab Allocation的主要术语 · 在Slab中缓存记录的原理 · Slab Allocator的缺点 · 使用Gro ...

  9. memcached全面剖析–2.理解 memcached的内存存储

    來源:http://tech.idv2.com/2008/07/11/memcached-002/ 作者charlee 版权声明 :可以任意转载,但转载时必须标明原作者charlee.原始链接http ...

最新文章

  1. leach协议matlab仿真代码
  2. apache开源项目--ApacheDS
  3. OpenCV图像翻转:flip()函数的使用
  4. android xml: xliff:g
  5. MVC架构 -- 初学试水选课管理系统
  6. Joda-Time几个用法小记
  7. 新手程序员不知道的小技巧!
  8. 制作win10安装u盘_最简单的Win10系统安装U盘制作方法
  9. .net 下URL重写
  10. 扩大mysql的cpu_MySQL CPU占用超过100%
  11. 大企业都在用的开源 ForgeRock OpenAM 被曝预认证 RCE 0day
  12. 计算机教师专业要求,计算机专业教师技能达标要求
  13. Hadoop的安装和使用
  14. 2017年第六届数学中国数学建模国际赛(小美赛)比赛心得
  15. JAVA失物招领系统毕业设计 开题报告
  16. 有道云笔记怎么保存html,有道云笔记怎么保存网页?有道云笔记保存网页技巧...
  17. 小程序php文档,微信小程序API 文件
  18. 跨站脚本(XSS)攻击
  19. 20180402-F · US Tuition Costs · pheatmap 绘制热图 · R 语言数据可视化 案例 源码
  20. 早期RA获超声缓解的基线预测因素

热门文章

  1. Dubbo支持哪些协议?各有什么特点?
  2. 用ATL创建COM组件(详细分析了ATL创建的各种文件的意义,看完之后ATL就入门了)
  3. 一款简单强大的下载软件(freedownloadmanager)
  4. 深圳地铁将开通免费WiFi,借此机会了解一下,使用WiFi的安全
  5. c# 字符串转时间的方式
  6. 用图片填充为文字背景技巧
  7. 10分钟掌握表情包,1小时画出挤娃娃!
  8. 阿里云CN域名注册、续费、转入和赎回价格表
  9. python实训项目
  10. Linux下安装MongoDB的Database Tools并配置(mongodump: command not found)?