在嵌入式实时操作系统中使用malloc()和free()的危险

前言

本文会从以下几个方面阐述使用malloc()free()函数动态的分配/释放内存的危害。

存在的问题

在嵌入式中无法很难实现对内存的动态映射(虚拟内存机制),尤其是裸机中。即使在嵌入式操作系统中,因为是实时性的要求,很少会用动态映射。

嵌入式设备自身RAM较小

嵌入式设备中RAM往往就几百KB大小,在小型的嵌入式设备中会更加紧张,RAM的使用更是寸土寸金。

函数自身的实现较为复杂

malloc()free()自身的实现就比较复杂,自身就占据了很大一块代码空间。

安全性

在申请内存,使用完毕后,必须需要手动释放,若不及时释放容易造成内存泄漏。

另外malloc函数常会表现出极其不可预测的特性,在多核多系统上进行多线程开发往往会遇到问题。

在signal中使用会产生错误与陷阱。

参考文章:https://blog.csdn.net/qq_40334837/article/details/96423711

不确定性

每次调用内存分配与释放函数执行的时间可能都不一样。每次申请内存都需要根据存储数据的长度,在内存中寻找一个合适大小的空闲内存块,然后将数据存储在内存块中。而寻找这样一个空闲内存块所耗费的时间是不确定的,因此对于实时系统来说,是不可接受的。

实时操作系统必须保证内存块的分配在可预测的时间内完成,否则实时任务对外部事件的响应也将变得不可确定。

会造成内存碎片化

过多的mallocfree容易造成内存碎片,致使可使用的堆内存变小。尤其是在对单片机等没有MMU的芯片编程时,慎用mallocfree

在分配和释放过程中,会使内存空间中存在一些小的内存块,它们的地址不连续,不能够作为连续的内存块分配,所以一定会在某个时间,系统已经无法分配到合适的内存,导致系统瘫痪。

使链接器配置更加复杂

可能覆盖其它地方内存

如果允许堆空间的生长方向覆盖其他变量占据的内存,它们会成为debug的灾难。

解决方案

内存池

内存池(Memory Pool),又被称为固定大小区块规划(fixed-size-blocks allocation),允许程序员以类似 C语言 的 malloc 或是 C++ 的 new 操作数进行动态的存储器规划。对于其它动态存储器规划的实践来说,因为会变动存储器区块大小导致的碎片问题,导致在实时系统上受限于性能因此,根本无法使用。内存池提供了一个更有效率的解决方案:预先规划一定数量的存储器区块,使得整个程序可以在运行期规划 (allocate)、使用 (access)、归还 (free) 存储器区块。
有许多实时操作系统采用了内存池。

优点:

  1. 效率高,先后对来说简单,且时间复杂度低
  2. 每次申请的大小都是固定的,可以有效地防止内存碎片化。
  3. 简单,易实现。
  4. 内存的申请和释放都在可控范围之内。

RTOS内存管理模块

当前市面上的绝大部分RTOS (例如ucosRT-ThreadliteOS等)都实现了内存管理模块,可以根据各RTOS的方法进行申请释放内存。

最后

笔者才疏学浅,对此理解还不是很深刻,对底层理解有限,写此文只是总结个人目前对此的理解,后续若还有深入,必会更新。同时希望大佬多多指点!

猜你喜欢

转载自blog.csdn.net/qq_45628620/article/details/116767129
今日推荐