关注+星标公众,不错过精彩内容

转自 | Mculove666

今天分享一点关于RTOS内存管理方面的内容。

阅读本文之前,建议先了解一下RTOS抢占式调度机制和时间片调度机制等相关内容。


1. 知识点回顾

1.1. 静态内存

uint8_t buffer[128];

当你写下这行代码时,就意味着你使用了128字节的静态内存,buffer的空间由编译器静态分配到栈中,且程序运行过程中,buffer的大小无法改变,这就称之为静态内存。

1.2. 动态内存

void *buffer_ptr = NULL;
buffer_ptr = malloc(128 * sizeof(uint8_t));

当你写下这行代码时,就意味着你使用了128字节的动态内存,buffer在程序运行时从堆中分配指定大小的空间,且不用的时候可以使用free释放,归还给堆空间。

2. RTOS中的动态内存管理

2.1. 为什么需要动态内存管理

静态内存由编译器分配,这个没什么好说的~

一般情况下使用malloc申请分配动态内存有两个缺陷:

① 由于分配算法的复杂度和堆空间的使用情况,分配的时间不定;

② 在不断申请、释放的过程中,容易因为内存对齐而产生碎片化内存;

这两个缺陷在「实时」操作系统中是不允许的,所以操作系统必须提供一套有效、合理、时间可确定的动态内存管理机制。

2.2. 如何进行动态内存管理

既然传统malloc存在两个缺陷,那就抱着解决这两个缺陷的目的出发,去建立一套更适合于嵌入式系统的动态内存管理系统。

目前有两种不同的解决方案:动态内存堆管理算法(mmheap)和静态内存池管理算法(mmblk),两种方法各有优缺点,TencentOS-tiny中两种管理算法都提供,接下来依托具体算法进行讲述。

3. 动态内存堆管理算法

3.1. TLSF算法

TLSF全称Two-Level Segregated Fit memory allocator,两级隔离Fit内存分配器,是一款通用的动态内存分配器,专门设计用于满足实时要求。

https://github.com/mattconte/tlsf

这款TLSF动态内存分配器具有以下特点:

  • malloc,free,realloc,memalign的算法复杂度变为O(1);

  • 每次分配的开销极低(4字节);

  • 低碎片化

  • 支持动态添加和删除内存池区域

TLSF主要采用两级位图(Two-Level Bitmap)与分级空闲块链表(Segregated Free List)的数据结构管理动态内存池(memory pool)以及其中的空闲块(free blocks),用Good-Fit的策略进行分配。

本文不对此算法进行深入讲解(博主太菜~),如果感兴趣可以查找TLSF算法论文阅读,这里我只从应用角度给出一些需要注意的点:

「TLSF算法分配速度不一定快,只是说能保证分配的时间是个常数」(malloc不能保证);

② TLSF也叫多内存堆管理算法,「支持动态增加或者删除多块不连续的内存」,将它们作为一个内存堆使用;

3.2. TencentOS-tiny中的实现

TencentOS-tiny中此算法的实现的动态内存分配器在tos_mmheap.htos_mmheap.c中,其中默认指定最大可管理的不连续内存堆有三个,可以自行修改:

#define K_MMHEAP_POOL_MAX 3

TencentOS-tiny中提供了默认的一个缓冲区作为堆空间,在tos_global.c中定义:

uint8_t k_mmheap_default_pool[TOS_CFG_MMHEAP_DEFAULT_POOL_SIZE] __ALIGNED__(4);

大小在tos_config.h中指定:

#define TOS_CFG_MMHEAP_EN               1u#define TOS_CFG_MMHEAP_DEFAULT_POOL_SIZE        0x8000

3.3. mmheap使用示例

/***@brief   打印当前mmeheap使用情况*@param   none*@retval  none
*/
int list_mmheap_info(void)
{k_err_t err;k_mmheap_info_t mmheap_info;err = tos_mmheap_check(&mmheap_info);if (err != K_ERR_NONE) {printf("current mmheap info check fail, err = %d\r\n", err);return -1;}else {printf("current mmheap info:\r\n\tused: %d[0x%08x] free:%d[0x%08x]\r\n\r\n", mmheap_info.used, mmheap_info.used, mmheap_info.free, mmheap_info.free);return 0;}
}void task1_entry(void *arg)
{   void *ptr = NULL;size_t size;/* 输出块大小的最大值 */printf("K_MMHEAP_BLK_SIZE_MAX is %d(0x%08x) bytes\r\n\r\n", K_MMHEAP_BLK_SIZE_MAX, K_MMHEAP_BLK_SIZE_MAX);/* 打印当前内存使用情况 */list_mmheap_info();/* 申请一块内存使用 */size = 128;ptr = tos_mmheap_alloc(size);if (ptr == NULL) {printf("%d bytes mem alloc fail\r\n", size);}else {printf("%d bytes mem alloc success, ptr is 0x%08x\r\n\r\n", size, (uint32_t)ptr);}/* 打印当前内存使用情况 */list_mmheap_info();/* 释放申请的内存 */tos_mmheap_free(ptr);printf("mem free success\r\n\r\n");/* 打印当前内存使用情况 */list_mmheap_info();while (1) {tos_task_delay(1000);}
}

运行结果为:

4. 静态内存池管理算法

4.1. 管理机制

静态内存池就是将一块内存划分为n个大小相等的块,用户可以动态的申请、释放一个块,假装在使用动态内存。

4.2. TencentOS-tiny中的实现

TencentOS-tiny中静态内存池管理算法的实现在tos_mmblk.htos_mmblk.c中。

提供如下四个API:

//创建一个内存池
__API__ k_err_t tos_mmblk_pool_create(k_mmblk_pool_t *mbp, void *pool_start, size_t blk_num, size_t blk_size);//销毁一个内存池
__API__ k_err_t tos_mmblk_pool_destroy(k_mmblk_pool_t *mbp);//申请内存池中的一个空闲块
__API__ k_err_t tos_mmblk_alloc(k_mmblk_pool_t *mbp, void **blk);//释放回内存池一个内存块
__API__ k_err_t tos_mmblk_free(k_mmblk_pool_t *mbp, void *blk);

4.3. 静态内存块使用示例

typedef struct blk_st {int   id;char* payload;
} blk_t;#define BLK_NUM 10k_mmblk_pool_t mmblk_pool;
uint8_t mmblk_pool_buffer[BLK_NUM * sizeof(blk_t)];void task1_entry(void *arg)
{   blk_t *ptr = NULL;k_err_t err;/* 打印出一个块的大小 */printf("block size is %d bytes\r\n", sizeof(blk_t));/* 申请一个块 */err = tos_mmblk_alloc(&mmblk_pool, (void*)&ptr);if (err != K_ERR_NONE) {printf("a mmblk alloc fail, err = %d\r\n", err);return;}else {printf("a mmblk alloc success\r\n");}/* 使用该块 */ptr->id = 1;ptr->payload = "hello";printf("mmblk id:%d payload:%s\r\n", ptr->id, ptr->payload);/* 使用完毕之后释放 */err = tos_mmblk_free(&mmblk_pool, ptr);if (err != K_ERR_NONE) {printf("a mmblk free fail, err = %d\r\n", err);return;}else {printf("a mmblk free success\r\n");}while (1) {tos_task_delay(1000);}
}

运行结果如图:

5. 总结

本节主要讲述了使用malloc和free的缺点:申请时间未知,内存容易产生碎片。

所以在实时操作系统中诞生了动态堆管理机制和静态内存池管理机制,两种比较如下:

① 内存堆(mmheap)管理机制,每次可以申请和释放「不定大小的内存」,分配时间虽然不快,但是能保证已知;

② 静态内存池(mmblk)管理机制,每次只能申请和释放一个块(「固定大小的内存」),分配时间最快,没有碎片。

------------ END ------------

后台回复『RTOS』『MCU』相关文章。

欢迎关注我的公众号回复“加群”按规则加入技术交流群,回复“1024”查看更多内容。

欢迎关注我的视频号:

点击“阅读原文”查看更多分享,欢迎点分享、收藏、点赞、在看。

RTOS中动态内存和静态内存管理机制相关推荐

  1. C++中的堆内存、栈内存和静态内存

    C++中的堆内存.栈内存和静态内存 C++中的空间主要分为三类,堆内存.栈内存和静态内存,其中静态内存用来存储全局对象(定义在任何函数之外的对象).局部static对象.类static数据成员,栈内存 ...

  2. Linux系统中动态库和静态库的区别

    Linux系统中"动态库"和"静态库"那点事儿 今天我们主要来说说Linux系统下基于动态库(.so)和静态(.a)的程序那些猫腻.在这之前,我们需要了解一下源 ...

  3. JSP中动态includ与静态includ的区别

    JSP中动态INCLUDE与静态INCLUDE的区别? 动态INCLUDE用jsp:include动作实现 <jsp:include page="included.jsp" ...

  4. jsp中动态include与静态include的区别

    JSP中动态INCLUDE与静态INCLUDE的区别 动态INCLUDE用jsp:include动作实现 <jsp:include page="included.jsp" f ...

  5. 动态内存与静态内存的区别

    1. 静态内存 静态内存是指在程序开始运行时由编译器分配的内存,它的分配是在程序开始编译时完成的,不占用CPU资源. 程序中的各种变量,在编译时系统已经为其分配了所需的内存空间,当该变量在作用域内使用 ...

  6. ios 开发中 动态库 与静态库的区别

    使用静态库的好处 1,模块化,分工合作 2,避免少量改动经常导致大量的重复编译连接 3,也可以重用,注意不是共享使用 动态库使用有如下好处: 1使用动态库,可以将最终可执行文件体积缩小 2使用动态库, ...

  7. linux系统中 库分为静态库和,Linux系统中“动态库”和“静态库”那点事儿-【经典好文】...

    今天我们主要来说说Linux系统下基于动态库(.so)和静态(.a)的程序那些猫腻.在这之前,我们需要了解一下源代码到可执行程序之间到底发生了什么神奇而美妙的事情. 在linux操作系统中,普遍使用E ...

  8. Linux系统中“动态库”和“静态库”那点事儿

    转自:https://blog.csdn.net/u010977122/article/details/52958330#commentBox 今天忙着编译库文件,中间遇到不少问题,看到这篇文章不错, ...

  9. Linux系统中“动态库”和“静态库”那点事儿【转】

    转自:http://blog.chinaunix.net/uid-23069658-id-3142046.html 今天我们主要来说说Linux系统下基于动态库(.so)和静态(.a)的程序那些猫腻. ...

  10. JVM内存区域划分及其管理机制

    java 虚拟机在执行java程序的过程中会把它所管理的内存划分为若干个不同的数据区域,如图.各个区域有各自的用途,以及创建时间和销毁时间,有的区域随着虚拟机进程启动而存在,有些区域则依赖用户线程的启 ...

最新文章

  1. iOS动画详解(学习动画看这一篇就够了)
  2. Cassandra数据模型设计最佳实践
  3. 软件工程:需求分析的20条法则
  4. 加班越久故障越多,如何跳出程序员的恶性循环?
  5. swoole 协程coroutine
  6. 深度学习:神经网络基础知识总结
  7. C51数据类型扩充定义
  8. ElasticSearch讲解
  9. 【转】VC 多线程中控制界面控件的几种方法
  10. MySQL 查询连接数并显示完整的processlist中info信息
  11. python编程和继承_python面向对象编程-继承与派生
  12. Python学习(5)——内置函数
  13. kubernetes视频教程笔记 (3)-Pod及其网络通讯方式
  14. console_init初始化的研究
  15. java json 反序列化_java-如何将json字符串反序列化为对象
  16. 发卡机构(POS收单行)代码表
  17. springboot整合mysql
  18. 【学习笔记】seckill-秒杀项目--(6)秒杀功能
  19. 快速导出PDF文件中所有图片(使用Adobe Acrobat 10 )
  20. 看完,感触很多 “IT技术开发人员获得成功的六大步骤”

热门文章

  1. day30 JavaWeb阶段——HTML基础(源码+w3cschool菜鸟教程)
  2. win10照片查看器_win10最好的看图软件?win10照片查看软件推荐
  3. acunetix导出html,关于Acunetix v11 WebUI下不得不说的事情!
  4. 解决:地址 localhost:8080 已在使用中
  5. Java Se 、JavaEE、JavaME区别
  6. Mimics 21.0 安装
  7. Oracle数据库用户密码过期
  8. pdproxy度盘下载器不限速(xp版也可用) v2021
  9. cad线性标注命令_CAD中线性标注的快捷命令是什么
  10. 关于使用CAD文件预览的使用