FreeRTOS Memory Management
Embedded Systems are usually resource limited systems with least to almost zero expansion capacity. Few of most critical resources on Embedded Systems includes Power (as embedded systems are usually battery powered) and memory (RAM, ROM). Embedded Systems usually face remote and harsh real time environment usually mobile or remotely deployed.
Power management and response time are usually the key parameters of Embedded Systems efficiency. A margin b/w the two depends upon the target application. For a remotely deployed Embedded System saving battery power is highly desirable while for other application like Car Airbag system, the response time is very very important as compared to battery power management. Memory management has direct relationship with Embedded Systems response performance as we will see in the subsequent sections.
The term Memory Management refers to allocating and deallocating appropriate memory at appropriate time to appropriate process. The focus of this tutorial is on how FreeRTOS manages memory for various FreeRTOS Tasks and other operations.
When talking about memory management, there are two main aspects associated with it.
- Memory allocation Strategy
- Memory allocation Algorithm
1. Memory allocation Strategy:
Memory allocation Strategy refers to the allocation of memory for various processes/tasks either Statically or Dynamically.
1.1 Static Memory allocation:
In static allocation memory, memory is assigned to various tasks/processes at compile time. At run-time every task/process just uses its assigned memory! This type of allocation is suitable for hard real-time systems.
The problem with this type of memory allocation is that the assigned memory can’t be freed/deallocated at run-time once allocated at compile time; Even if the process or allocated memory is no more required.
1.2 Dynamic Memory allocation:
In Dynamic Memory allocation, memory is managed at run-time from heap section. At run-time when a process requires memory, it is assigned memory from heap and when the memory is no more required, the memory is reclaimed so that it can be allocated to other processes.
The downside of Dynamic memory allocation is that memory allocation and deallocation requires time before which the process that made the request can’t start/use the memory. Second, there is no guarantee that memory will be allocated (in case if memory is full). These types of behavior are highly undesirable in case of real-time critical systems like car airbag etc. As the process takes relatively more time (depends on implementation) which can affect real-time response. That’s why dynamic memory allocation is discouraged in hard real-time systems.
2. Memory allocation Algorithm:
Memory allocation algorithm refers to the policy/algorithm used in detecting/tracking free memory and assigning it to a process. Till the memory is used by a process, its kept reserved unless the process itself releases the memory.
In Static allocation, no special algorithm is used. Memory for every process is explicitly declared and reserved at compile time. For Dynamic memory management, there exists various algorithms and usually comes as a part of toolchain c-library or can be provided manually. Common example of Dynamic memory management algorithms are Standard C-Library
calloc() for allocation and
free() for deallocation.
3. FreeRTOS Memory Management:
FreeRTOS provides very flexible and portable strategies to facilitate both static an dynamic memory allocation. Whether it is preferable to use static or dynamic memory allocation is dependent on the application, and the preference of the application writer. Both methods have pros and cons, and both methods can be used within the same RTOS application.
3.1 FreeRTOS Static Allocation:
Support for static memory allocation can be enabled via setting
configSUPPORT_STATIC_ALLOCATION to 1 in
FreeRTOSConfig.h file. If
configSUPPORT_STATIC_ALLOCATION is left undefined it will default to 0.
Static requires more coding on the part of the application writer and is a little more complex as there are additional function parameters, normally creates a higher RAM usage as everything is always allocated whether it is used or not, but is deterministic.
configSUPPORT_STATIC_ALLOCATION is set to 1 then the application writer must also provide two callback functions i.e.
vApplicationGetIdleTaskMemory() for Idle Task and
vApplicationGetTimerTaskMemory() for RTOS Daemon/Timer Service task. The prior is compulsory while the later is only required if
configUSE_TIMERS is set to 1 in
3.2 FreeRTOS Dynamic Allocation:
Support for dynamic memory allocation can be enabled via setting
configSUPPORT_DYNAMIC_ALLOCATION to 1 in
FreeRTOSConfig.h file. If
configSUPPORT_DYNAMIC_ALLOCATION is left undefined it will default to 0.
FreeRTOS provides various algorithms (heap_1,2,3,4,5.c explained bellow) as a part of FreeRTOS source code to be used as dynamic memory allocation algorithm. The source code for all these algorithms can be found inside
This is the simplest implementation of all. It does not permit memory to be freed once it has been allocated. It is suitable for applications that creates all the tasks, queues, semaphores, etc. required when the system boots, and then use all of these objects for the lifetime of program (until the application is switched off again, or is rebooted). Nothing ever gets deleted. Using this implementation, application can never delete a task, queue, semaphore, mutex, etc. once it is created.
The bright side of this memory allocation implementation is that its simplest having small footprint and its behavior is always deterministic (always takes the same amount of time to execute) and cannot result in memory fragmentation.
This is the enhanced version of Heap_1.c. Unlike Heap_1.c it allows memory be freed once allocated at run time. Which means using this scheme, an application can create and delete any of tasks, queues, semaphores, etc. on fly at run-time. This scheme uses a best fit algorithm. It does not combine adjacent free blocks into a single large block which can lead to memory fragmentation problem if application repeatedly deletes tasks, queues, semaphores, mutexes, etc.
This implements a simple wrapper for the standard C library
free() functions that will, in most cases, be supplied with your chosen compiler. The wrapper simply makes the
free() functions thread safe. Is not deterministic and when used, considerably increase the RTOS kernel code size. This should be the last option to select a memory allocation scheme.
Its an enhanced version of Heap_2.c. Like Heap_2.c it also uses first fit algorithm and, unlike scheme 2, it does combine adjacent free memory blocks into a single large block. It is suitable for application that repeatedly deletes tasks, queues, semaphores, mutexes, etc. Like Heap_2.c it also not deterministic but takes care of fragmentation problem that Heap_2.c can cause.
Heap_5.c like Heap_4.c uses first fit algorithm and takes care of fragmentation problem during memory management. Unlike Heap_4.c, Heap_5.c has support for multiple non adjacent (non-contiguous) memory regions.
pvPortMalloc(): All memory allocation schemes uses
pvPortMalloc() to allocate memory.
vPortFree(): All memory allocation schemes (except Heap_1.c which doesn’t support memory to be freed once allocated) uses
vPortFree() to free memory.
For more detail information on FreeRTOS kernel Memory Management, refer to the FreeRTOS Official website .