当前位置: 首页 > news >正文

RT_Thread——内存管理

文章目录

  • 一、为什么要自己实现内存管理
  • 二、RT-Thread 的内存管理方法
    • 2.1 小内存管理算法
    • 2.2 slab 管理算法
    • 2.3 memheap 管理算法
  • 三、Heap 相关的函数
    • 3.1 rt_system_heap_init
    • 3.2 rt_malloc/rt_realloc/rt_calloc
    • 2.3 rt_free
    • 2.4 rt_malloc_sethook/rt_free_sethook

一、为什么要自己实现内存管理

后续的章节涉及这些内核对象:thread(线程)、messagequeue(消息队列)、semaphore(信号量)和rt_event(事件集)等。

为了让RT-Thread 更容易使用,这些内核对象一般都是动态分配:用到时分配,不使用时释放

使用内存的动态管理功能,简化了程序设计:不再需要小心翼翼地提前规划各类对象,简化API 函数的涉及,甚至可以减少内存的使用。

内存的动态管理是 C 程序的知识范畴,并不属于 RT-Thread 的知识范畴,但是它跟 RT-Thread 关系是如此紧密,所以我们先了解它。

在C语言的库函数中,有mallc、free等函数,但是在RT-Thread 中,它们不适用:

  • 不适合用在资源紧缺的嵌入式系统中
  • 这些函数的实现过于复杂、占据的代码空间太大
  • 并非线程安全的(thread-safe)
  • 运行有不确定性:每次调用这些函数时花费的时间可能都不相同
  • 内存碎片化
  • 使用不同的编译器时,需要进行复杂的配置
  • 有时候难以调试

注意:我们经常"堆栈"混合着说,其实它们不是同一个东西:

  • 堆,heap,就是一块空闲的内存,需要提供管理函数
    • malloc:从堆里划出一块空间给程序使用
    • free:用完后,再把它标记为"空闲"的,可以再次使用
  • 栈,stack,函数调用时局部变量保存在栈中当前程序的环境也是保存在栈中
    • 可以从堆中分配一块空间用作栈

在这里插入图片描述

二、RT-Thread 的内存管理方法

RT-Thread 中内存管理的接口函数为:rt_malloc 、rt_free,对应于 C 库的 malloc、free。

RT-Thread 为了满足不同的需求,提供三种内存栈管理方法,三种方法都使用一样的函数进行操作。

在系统运行时只能选择其中一种方法,甚至可以不使用内存堆管理机制也可以:代码里不调用rt_malloc 函数

在这里插入图片描述

通常在 Keill 工程目录,可以找到 rtconfig.h,可以在里面配置这些宏之一,选择某个文件:

  • RT_USING_SMALL_MEM:默认使用的是小内存管理算法(SMALL_MEM)
  • RT_USING_SLAB:slab 管理方法
  • RT_USING_MEMHEAP:memheap 管理方法
/* Memory Management */ 
##define RT_USING_HEAP            /* 使用堆 */ 
##define RT_USING_SMALL_MEM       /* 使用哪种堆管理方法 */ 
##define RT_USING_MEMPOOL         /* 使用内存池: 从堆里分配内存后进行二次管理 */ 

2.1 小内存管理算法

小内存管理算法是最简单的内存分配算法,需要内存就分割一块:

  • 初始时,内存是一块大内存,需要分配内存时,从这块大内存分割一块内存
  • 每块内存,都包含一个管理用的数据头,里面有指向下一个内存块的指针,通过链表的形式串起来
  • 数据头包含四个成员:magic(一个固定值,作为标志指示内存块是否被非法改写)、used(指示内存是否分配使用)、next(指向下一个块内存)、prev(指向上一块内存)

使用小内存管理算法时,内存分配过程如下图所示:

在这里插入图片描述

  • 假设已经使用这个方法管理了内存,当前时刻空闲链表指针 lfree 指向大小为32字节的内存块
  • 当用户需要分配一个64字节的内存块时,lfree指向的内存块只有32字节不能满足要求,内存管理器会继续寻找下一内存块
  • 下一内存块只有60字节,而且已经分配了,因此继续寻找下一内存块
  • 下一内存块有128 字节,且没有使用过,满足需求,但这块内存比较大,分配器会将剩下的内存块,继续放在链表中
  • 这里内存块原来为128字节,使用64字节,另外数据头占据12字节,就只剩下52字节

内存释放过程如下:

  • 释放时,分配器查看前后相邻的内存块是否空闲,如果空闲则合并为一块大内存

2.2 slab 管理算法

小内存管理算法需要频繁的分配、释放内存,可能会影响系统效率。

当系统内存比较大,我们可以提前分配好若干大小的内存块,直接供给线程使用,可以一定程度的提高效率,但会浪费一些内存。

slab 管理方法的核心在于有多个链表,每个链表中存放相同大小的内存块:

  • 每个 zone_array 数据项就是一个链表,里面存放有多个 zone,zone 里有多个固定大小的小内存块
    • zone_array[0]里存放这些 zone,它们被分为小内存块,这些小内存块大小都是8字节
    • zone_array[1]里存放这些 zone,它们被分为小内存块,这些小内存块大小都是16字节
    • zone_array[71]里存放这些 zone,它们被分为小内存块,这些小内存块大小都是16K字节

在这里插入图片描述

下面以情景分析的方法演示slab管理方法,假设想分配32字节的空间:

  1. 初始状态:zone_array[3]为空
    在这里插入图片描述
  2. 调用rt_malloc(32),发现zone_array[3]为空,于是向页分配器申请一大块内存,这被称为zone
    在这里插入图片描述
  3. 从这个zone中,分配得到一个小内存块,它被称为chunk:下图中32字节的小内存被称为chunk
    在这里插入图片描述
  4. zone_array[3]指向 zone,并且 rt_malloc(32)返回这个 chunk
  5. 再次调用rt_malloc(32),发现zone_array[3]非空,于是从这个 zone 中继续分配 32 字节的chunk:
    在这里插入图片描述
    下面再次以情景分析的方法演示slab 管理方法,假设释放上面分配得到的2 个chunk:

(1) 这两个chunk 会被放入zone的z_freechunk 链表:
在这里插入图片描述
(2) 这时这个zone 就全部是空闲状态,如果zone_array[3]还有其他zone 可用于分配内存,那么这个全部空闲的zone就会从zone_array[3]中移除,放入zone_free 链表

2.3 memheap 管理算法

在嵌入式系统中,除了芯片内部的内存,可能还会外扩内存。

memheap 管理算法就是针对这种情况,可以将多个地址不连续的内存堆,组成一个大的内存堆

RT-Thread 通过 memheap_item 链表,将多个内存堆进行连接。

当分配内存时,会先尝试从默认的内存堆分配内存,当分配失败时,再去 memheap_item 链表一次尝试其它内存堆

对于用于的应用程序而言,不用关心内部实现,就当作在一个内存堆上操作。

在这里插入图片描述

这三种算法,可以比作吃西瓜:

  • 对于小内存管理算法:一个西瓜,自己要吃多少,就去切多少
  • 对于slab 管理算法:一个西瓜,已经切好了若干大小,自己要吃多少,就去拿对应大小的
  • 对于memheap管理算法:两个西瓜,第一个吃完了,就去吃第二个

三、Heap 相关的函数

3.1 rt_system_heap_init

函数原型:

void rt_system_heap_init(void* begin_addr, void* end_addr);

作用:如果要使用内存堆,必须调用该函数进行初始化堆,参数为堆的开始地址和结束地址

该函数通常在 board.cdrv_common.c 等类似的系统初始化里

3.2 rt_malloc/rt_realloc/rt_calloc

函数原型:

void *rt_malloc(rt_size_t nbytes); 
void *rt_realloc(void *rmem, rt_size_t newsize); 
void *rt_calloc(rt_size_t count, rt_size_t size); 

作用:

  • rt_malloc:从内存堆中找到 nbytes 大小的内存,返回内存块地址
  • rt_realloc:将已分配的内存 rmem 重新分配为 newsize 大小。若大小增加,原来的内存块数据不变;若缩小,后面的数据将被截断
  • rt_calloc:从内存堆中分配 count 个,大小为 size 的内存块,返回首个内存块的地址

2.3 rt_free

函数原型:

void rt_free (void *ptr); 

作用:申请的内存使用完后,必须调用该函数进行释放,否则会造成内存泄漏

2.4 rt_malloc_sethook/rt_free_sethook

函数原型:

void rt_malloc_sethook(void (*hook)(void *ptr, rt_size_t size)); 
void rt_free_sethook(void (*hook)(void *ptr)); 

作用:

  • rt_malloc_sethook:内存分配完成后,将回调本函数,用户可以自己设置钩子函数的内容
  • rt_free_sethook:内存释放完成前,将回调本函数,用户可以自己设置钩子函数的内容

相关文章:

  • 融云 uni-app IMKit 上线,1 天集成,多端畅行
  • 什么是国密、密评、商密
  • 离线服务器算法部署环境配置
  • sqlsugar查看表结构并导出word文档
  • 深入理解用于中断控制的 NVIC 寄存器
  • STM32之串口通信WIFI上云
  • PyTorch中cdist和sum函数使用详解
  • 25、工业防火墙 - 工控网络保护 (模拟) - /安全与维护组件/industrial-firewall-dcs-protection
  • 免费的DDOS防护对网站业务有用吗?
  • PEFT库PromptTuningConfig 配置
  • Google I/O 2025:Gemini 2.5 Pro、Project Astra 与 AI Ultra 全面解析
  • Gartner研究报告《Generative AI 赋能Digital Commerce的三种路径》学习心得
  • Python人工智能算法 模拟退火算法:原理、实现与应用
  • 阿里云合集(不定期更新)
  • 【Vue篇】重剑无锋:面经PC项目工程化实战面经全解
  • RuntimeError: Cannot find sufficient samples, consider increasing dataset size.
  • Linux上运行程序加载动态库失败
  • 【完整版】基于laravel开发的开源交易所源码|BTC交易所/ETH交易所/交易所/交易平台/撮合交易引擎
  • GO语言学习(七)
  • 港股IPO市场火爆 没有港卡如何参与港股打新?
  • 猪八戒网怎么做网站/关键词搜索量怎么查
  • 网站建设网站定制/百度手机助手官网
  • 北京网站案例/营销软文广告