嵌入式开发为什么不能使用malloc()?

更新时间: 2021-11-26 11:00:51来源: 粤嵌教育浏览量:10542

  我发现许多嵌入式软件开发人员都提出了一个特别有趣的话题,那就是动态内存分配——在需要时获取内存块,这种看似简单的常规操作带来了大量问题。这些并不局限于嵌入式开发——许多桌面应用程序都会出现内存泄漏,影响性能,并可能导致系统重新启动。但是,我担心嵌入式开发环境。


  通常不建议将malloc()用于嵌入式应用程序的原因有很多:


  1.该函数通常不可重入(线程友好),因此在实时操作系统中使用它可能具有挑战性。


  2.它的性能是不确定的(可预测的),因此分配内存块所需的时间可能非常可变,这在实时应用程序中是一个挑战。


  3.内存分配可能失败。


  虽然这些都是有效的观点,但它们可能并不像看上去那么重要。


  只有从多个线程调用函数时,才存在可重入性问题。编写可重入的malloc()函数是完全可行的,但也可以使用标准版本,使重入变得不必要。只需将所有内存分配活动本地化为单个任务。你甚至可以创建一个任务,其唯一功能是动态内存分配;其他任务只需发送一条消息,请求分配或释放内存块。



  决定论并非总是必需的。非实时应用程序是实时的,非实时应用程序并不一定要求其操作的所有部分都具有确定性。


  分配失败可能是一个问题,但它是可以管理的。如果无法分配请求的内存,则malloc()函数将返回空指针,嵌入式开发人员必须检查此响应并采取适当的措施。如果故障是由于内存耗尽造成的,则很可能存在设计缺陷—没有为堆分配足够的内存。然而,分配失败的一个常见原因是堆碎片;有足够的可用内存,但它不在连续区域中。这种碎片的产生是因为内存以随机方式分配和释放,导致内存的分配区域和空闲区域。


  尽管它不可预测,malloc()还有另一个问题——它的速度往往相当慢。这并不奇怪,因为函数的功能相当复杂。基于块的分配器的内在简单性非常有效地解决了这个问题。


  但是,如果应用程序在不可预测的时间确实需要随机大小的内存块,该怎么办?


  实现这种灵活性,同时避免碎片和不确定性的一种方法是构建一个分配器,根据请求的内存块大小从多个“池”中选择块。为池选择块大小的一个好方法(如果你事先不知道将需要的块大小)是使用几何级数,如16、32、64、128字节。然后,分配将如下所示:



  显然,有些分配会非常有效:16字节池中有16个字节,来自32字节池的31字节;来自16字节池的9字节;来自128字节池的65字节。总的来说,这些低效率对于速度、决定论和消除碎片化的好处来说只是一个很小的代价,可以提高嵌入式开发效率。

免费预约试听课