如何更改 FreeRTOS 中任务的最大可用堆大小?

Posted

技术标签:

【中文标题】如何更改 FreeRTOS 中任务的最大可用堆大小?【英文标题】:How can I change maximum available heap size for a task in FreeRTOS? 【发布时间】:2015-08-09 05:51:40 【问题描述】:

我正在通过以下方式在任务中创建元素列表:

        l = (dllist*)pvPortMalloc(sizeof(dllist));

dlllist 是 32 字节大。 我的嵌入式系统有 60kB SRAM,所以我希望系统可以轻松处理我的 200 个元素列表。我发现在为 8 个元素分配空间后,系统在第 9 次 malloc 函数调用(256byte+)时崩溃。

如果可能,我可以在哪里更改 freeRTOS 中的堆大小? 我可以以某种方式请求堆大小的当前状态吗? 我在文档中找不到此信息,因此我希望有人可以提供有关此问题的一些见解。 提前致谢!

【问题讨论】:

“可用堆空间的总量由configTOTAL_HEAP_SIZE 设置 - 在FreeRTOSConfig.h 中定义。” freertos.org/a00111.html(内存管理)。 @WeatherVane:这取决于他使用的内存分配器。上次我查看这些时,有 4 种不同的类型(没有一个符合项目的要求)。 @Weather Vane:谢谢你的设置和 Richard 提到的功能,让我找到了解决方案,我将堆大小增加到 25 kB,现在它运行顺利。我观察到的一件有趣的事情是,增加任务的 STACK 大小也会增加可用的 HEAP 大小。我想知道这是什么原因。 【参考方案1】:

对于标准分配器,您可以在 FreeRTOSConfig.h 中找到一个配置选项。

但是: 根据使用的分配器,很可能您已经用完了内存。 IIRC 有一个不 free() 任何块(free() 只是一个假人)。所以返回的任何块都将丢失。如果您只分配内存,这仍然很有用,例如在启动时,然后使用你所拥有的。

其他分配器可能不会在返回后合并相邻块,从而比成熟的分配器更快地增加碎片。

此外,您可能会因为碎片而丢失内存。根据您的分配/释放模式,您很快可能会得到一个看起来像瑞士奶酪的堆:分配的块之间有很多洞。因此,虽然仍有足够的可用内存,但没有一个块足够大来满足所需的大小。

如果您只在那里分配大小相同的块,您最好使用自己的分配器或池(固定大小的块)。 Thaqt 将在启动期间被静态分配(例如数组)并链接为链表。然后 Alloc/free 将只是在堆栈上推送/弹出(或放入/获取队列)。这也将非常快并且复杂度为 O(1)(如果编写得当,中断安全)。

请注意,普通的 malloc()/free() 不是中断安全的。

最后:不要投void *。 (嗯,这实际上是标准 malloc() 返回的内容,我希望 FreeRTOS-variant 也会这样做)。

【讨论】:

我正在使用 heap4 中的 alloc 函数,它应该可以防止碎片,特别是如果系统在崩溃之前只分配了几块内存。事实上,我正在为我的内存块使用链表。 一个普通的分配器实际上并不能防止碎片,只能减少,除非你不释放或单独使用单个块大小。对于后者,池会更容易和更快。但是,我只是查看了可用的分配器并编写了自己的分配器。主要是因为我在 Cortex-M 中使用 MPU,需要自然对齐的块以及字对齐的块。【参考方案2】:

(是 - FreeRTOS pvPortMalloc() 返回 void*。)

如果您有 60K 的 SRAM,并且 configTOTAL_HEAP_SIZE 很大,那么在分配 256 个字节后,您不太可能用完堆除非您几乎没有剩余的堆。许多 FreeRTOS 演示将继续创建对象,直到使用所有堆,因此如果您的应用程序基于其中之一,那么在执行代码之前您的堆将不足。您可能还做过一些事情,比如通过创建具有大量堆栈的任务来耗尽大量堆空间。

heap_4 和 heap_5 将合并相邻的块,这将尽可能减少碎片,但我认为这不是你的问题 - 特别是因为你没有提到在任何地方释放任何东西。

除非您使用 heap_3.c(它只是使标准 C 库 malloc 和空闲线程安全),否则您可以调用 xPortGetFreeHeapSize() 来查看您有多少空闲堆。您可能还可以使用 xPortGetMinimumEverFreeHeapSize() 来查询您离堆用完的距离有多近。更多信息:http://www.freertos.org/a00111.html

您还可以定义一个 malloc() 失败的钩子 (http://www.freertos.org/a00016.html) 以获得 pvPortMalloc() 返回 NULL 的即时通知。

【讨论】:

我没有使用演示代码,也没有进行其他分配,我的代码正在使用 heap_4,它也在释放内存,但我认为在 4x32byte mallocs 之后碎片不会成为问题.我将使用 xPortGetFreeHeapSize() 并在完成后报告,谢谢:) 感谢使用这些功能,我可以找出真正的问题(如果您想知道,请参阅我的问题下方的评论):)

以上是关于如何更改 FreeRTOS 中任务的最大可用堆大小?的主要内容,如果未能解决你的问题,请参考以下文章

FreeRTOS队列

是否可以动态更改最大 Java 堆大小?

ucos 怎样确定任务堆栈大小

FreeRTOS官方翻译文档——第二章 队列管理

如何确定freertos任务的栈使用情况

FreeRTOS 任务优先级和堆栈大小