传感器|嵌入式开发为什么不能使用malloc()

传感器|嵌入式开发为什么不能使用malloc()

文章图片


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

通常不建议将malloc()用于嵌入式应用程序的原因有很多:
1.该函数通常不可重入(线程友好) , 因此在实时操作系统中使用它可能具有挑战性 。
2.它的性能是不确定的(可预测的) , 因此分配内存块所需的时间可能非常可变 , 这在实时应用程序中是一个挑战 。
【传感器|嵌入式开发为什么不能使用malloc()】3.内存分配可能失败 。
虽然这些都是有效的观点 , 但它们可能并不像看上去那么重要 。
只有从多个线程调用函数时 , 才存在可重入性问题 。 编写可重入的malloc()函数是完全可行的 , 但也可以使用标准版本 , 使重入变得不必要 。 只需将所有内存分配活动本地化为单个任务 。 你甚至可以创建一个任务 , 其唯一功能是动态内存分配;其他任务只需发送一条消息 , 请求分配或释放内存块 。

决定论并非总是必需的 。 非实时应用程序是实时的 , 非实时应用程序并不一定要求其操作的所有部分都具有确定性 。
分配失败可能是一个问题 , 但它是可以管理的 。 如果无法分配请求的内存 , 则malloc()函数将返回空指针 , 嵌入式开发人员必须检查此响应并采取适当的措施 。 如果故障是由于内存耗尽造成的 , 则很可能存在设计缺陷—没有为堆分配足够的内存 。 然而 , 分配失败的一个常见原因是堆碎片;有足够的可用内存 , 但它不在连续区域中 。 这种碎片的产生是因为内存以随机方式分配和释放 , 导致内存的分配区域和空闲区域 。
尽管它不可预测 , malloc()还有另一个问题——它的速度往往相当慢 。 这并不奇怪 , 因为函数的功能相当复杂 。 基于块的分配器的内在简单性非常有效地解决了这个问题 。
但是 , 如果应用程序在不可预测的时间确实需要随机大小的内存块 , 该怎么办?
实现这种灵活性 , 同时避免碎片和不确定性的一种方法是构建一个分配器 , 根据请求的内存块大小从多个“池”中选择块 。 为池选择块大小的一个好方法(如果你事先不知道将需要的块大小)是使用几何级数 , 如16、32、64、128字节 。 然后 , 分配将如下所示:

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