在实时应用程序中使用 malloc

Use of malloc in Real Time application

我们的一个实时应用程序出现问题。这个想法是每 2 毫秒(500 赫兹)运行 一个线程。在应用程序 运行 半小时或一个小时后......我们注意到线程落后了。

经过几次讨论,人们抱怨实时线程中的 malloc 分配,或者根本原因是 malloc 分配。

我想知道,在实时线程中避免所有动态内存分配总是一个好主意吗?

互联网上这方面的资源很少?如果你能指出一些讨论,我们也会很棒..

谢谢

第一步是分析代码并确保您准确了解瓶颈所在。人们通常不善于猜测代码中的瓶颈,您可能会对这些发现感到惊讶。您可以自己简单地检测此例程的几个部分,并定期转储 min/avg/max 持续时间。你想看到最坏的情况(最大),如果平均持续时间随着时间的推移而增加。

我怀疑 malloc 会在能够 运行ning Linux 的合理微控制器上占据这 2ms 的任何重要部分;我想说的是,与性能问题相比,您更有可能 运行 由于碎片而导致内存不足。如果您的函数中有任何其他系统调用,它们很容易占用比 malloc.

多一个数量级

但如果 malloc 确实是问题所在,则取决于您的对象的寿命有多短、您可以浪费多少内存,以及您的要求是提前知道多少,有几种方法你可以采取:

  1. 通用分配malloc 来自您的标准库,或任何第三方实现):最好的方法是 "more than enough" RAM,许多短暂的对象,没有严格的延迟要求

    • 优点:适用于开箱即用的任何对象大小,熟悉的界面,动态共享内存,如果内存不是问题,则无需 "plan ahead"
    • 缺点:在分配 and/or 释放过程中有轻微的性能损失,在处理大量 allocations/deallocations 不同大小的对象时出现内存碎片问题,运行 时间分配是否会失败是确定性较低,在 运行 时间
    • 时无法轻易缓解
  2. 内存池:在内存有限、需要低延迟、对象需要比单个块作用域更长寿的大多数情况下的最佳方法

    • 优点:allocation/deallocation时间在任何合理的实现中都保证是O(1),不会产生碎片,更容易提前计划它的大小,无法在运行分配-时间(可能)更容易缓解
    • 缺点:适用于单个特定对象大小 - 内存不在程序的其他部分之间共享,需要规划正确大小的池或冒着潜在的内存浪费风险
  3. 基于堆栈的(自动持续时间)对象:最适合较小的、短暂的对象(单块作用域)

    • 优点:分配和解除分配是自动完成的,允许在对象的生命周期内优化使用 RAM,有些工具有时可以对代码进行静态分析并估计堆栈大小
    • 缺点:对象仅限于单个块范围 - 不能在中断调用之间共享对象
  4. 单个静态分配的对象:长寿命对象的最佳方法

    • 优点:没有任何分配 - 所有需要的对象都存在于整个应用程序生命周期中,allocation/deallocation
    • 没有问题
    • 缺点:如果对象应该是短暂的,则会浪费内存

即使您决定在整个程序中使用内存池,也要确保将 profiling/instrumentation 添加到您的代码中。然后将它永远留在那儿,看看性能如何随时间变化。

作为航空航天行业的实时软件工程师,我们经常看到这个问题。即使在我们自己的工程师内部,我们也看到软件工程师试图使用他们在别处学到的非实时编程技术或在他们的程序中使用开源代码。永远不要在实时期间从堆中分配。我们的一位工程师创建了一个工具来拦截 malloc 并记录开销。您可以在数字中看到您无法预测分配尝试何时会花费很长时间。即使在非常高端的计算机(72 核,256 GB RAM 服务器)运行 Linux 的实时混合上,我们记录的 mallocs 也需要 100 毫秒。这是一个跨环的系统调用,开销如此之高,你不知道什么时候会被垃圾收集击中,或者它什么时候决定必须为任务请求另一个大块或内存 OS.