FreeRTOS堆分配大小对任务数的影响

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了FreeRTOS堆分配大小对任务数的影响相关的知识,希望对你有一定的参考价值。

参考技术A FreeRTOS堆分配(内存)如果不够大,可能引起FreeRTOS运行异常。

对于STM32芯片, 如果使用STM32CubeMX配置FreeRTOS,创建4个任务时,会引起FreeRTOS运行异常,原因是cube默认是使用heap_4.c文件来动态分配内存,并将堆大小设置为3072,见FreeRTOSConfig.c文件中的定义:

                              #define configTOTAL_HEAP_SIZE ((size_t)3072)

这个堆大小可以满足创建3个任务,但如果创建4个任务,程序将运行异常。经过断点调试,可以看到一个任务在创建时需要申请约600个字节的内存(使用默认的任务堆栈深度为128,即128*4=512字节,TCP块占用84个字节,共596字节;对于不同的FreeRTOS配置,这个数值略有差异)。将上述的3072增加为3670,此时创建4个任务,再次运行正常了。

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

【中文标题】如何更改 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堆分配大小对任务数的影响的主要内容,如果未能解决你的问题,请参考以下文章

Java中的堆内存设置对线程创建数的影响以及-Xss参数的记录

FreeRTOSFreeRTOS学习笔记(13)— FreeRTOS创建任务和任务管理(原生API)

FreeRTOS 任务栈大小确定及其溢出检测

FreeRTOS 任务栈大小确定及其溢出检测

FreeRTOS中的任务堆栈溢出检测机制

FreeRTOS 任务优先级分配方案