Memory management of task heaps

anonymous wrote on Friday, May 20, 2011:

Hi everyone,

I’m working on a system using FreeRTOS as the base platform. In it, I create several tasks that perform various operations. Nothing new here. On top of this, I am trying to implement a Task Watchdog. Basically, the watchdog pings every task running in the system to make sure that it is running and responsive. In the case that a task becomes unresponsive, I want to reset that task and free any memory it has allocated for itself. In FreeRTOS, I can do most of this using vTaskDelete() and xTaskCreate() and wait for the idle task to free memory in the task’s stacl that is being reset. This works fine except for one thing. The memory that is freed is just the task stack which is managed by the RTOS (this is documented). This includes return addresses pushed to the stack by calls from the task and any local variables. All other memory allocated (namely from the heap via malloc() or new) is not freed by the RTOS. The problem is that in a multitasking environment, any task can allocate memory from the global heap provided by the compiler/linker. So, when I delete a task, I have to pick out all the individual memory blocks I allocated in the task in order to free it. Freeing the entire heap would wipe out memory for all tasks (something that would be catastrophic). Instead, I’d like to allocate a memory block (local heap) for a task when it is created. If I have to kill a task and free any memory that was allocated in that task, I simply free that task’s local heap. That feature is not provided in the official release of FreeRTOS.

Has anyone come across this problem? Do you have a solution or can you point me in the right direction?

Thanks for your help.

beethoven62

davedoors wrote on Saturday, May 21, 2011:

Allocating a heap to every task will require a lot of RAM. Most microcontrollers don’t have that much RAM, but assuming your system does…

The memory allocation is part of the portable layer. By default you get three options, see heap_1.c, heap_2.c and heap_3.c. You could easily add your own heap_x.c to use a thread heap instead of a global heap. You then need to allocate RAM from the global heap each time a task is created. Implementing the traceTASK_CREATE() macro might be the easiest way of doing that. traceTASK_CREATE() is called each time a task is created, and the macro parameter is a pointer to the task control block of the created task, so it has all the information you need.

That are also more basic ways of doing it. For example a task could manually add a pointer to each block it allocates to a linked list, and the traceTASK_DELETE macro implemented to walk the list and free() all the blocks it contains.

Also consider if you really want your tasks using dynamic memory allocation. If the system is big enough, fast enough, has enough memory, and does not care about the non deterministic behavior of malloc() then it would be ok.

Hope that helps.

beethoven62 wrote on Sunday, May 22, 2011:

Thanks for the quick reply. I was wondering why you say that allocating task heaps requires a lot of RAM. Other than a little bit of overhead, it should not require much more than if I allocate memory from a global heap. For argument’s sake, let’s say that I do have a lot of memory and my system is quite fast. I’m interested in two of your points. I’ll look into using the heap_2.c code to see if I can use the macro you mentioned (I presently use heap_2.c in my system). Thanks for giving me that tip. The other point is if I need to allocate heap space at all. Basically, I’ve implemented the C++ STL string type. I had to do this because my compiler does not support templates and that’s what the STL string type uses in the standard implementation. My string type does, however, dynamically allocate and deallocate memory because a C++ STL grows and shrinks in size at will (you probably already know that). Any suggestions on how could I implement this string type without a heap?

Another thing I was thinking of was hijacking the global heap pointer provided by the compiler/linker and allocating chunks of memory to tasks using this heap pointer via the “new” operator by overriding it.

Thanks again for your help.

beethoven62

rtel wrote on Sunday, May 22, 2011:

DaveDoors said “allocating a heap to every task”, presumably implying that each task would have its own memory area from which it allocated RAM, and that the size of all these separate heaps added together would be greater than having a single global heap.  It could be inefficient if some tasks only used a bit of their allocated heap while others used most of it.

Regards.

beethoven62 wrote on Monday, May 23, 2011:

OK guys. I basically know how much heap space I need since I’ve characterized my system. The question is how to manage it better than just using a global heap. Most of my tasks will not allocate any heap space because it doesn’t use any. Others will allocate a certain amount. All of this can be characterized and controlled. The only aspect is when a task stops functioning. I need to kill that task and resurrect it exactly as before.