Scan to FollowLearn Embedded Together, learn and grow together

This is a series of introductory articles on FreeRTOS, aimed at helping beginners quickly get started and master the basic principles and usage methods of FreeRTOS while organizing their own knowledge.
Quick Start with FreeRTOS – An Introduction to the System
FreeRTOS Official Chinese Website is Now Live
FreeRTOS Coding Standards and Data Types
Quick Start with FreeRTOS – Task Management
FreeRTOS Learning – Detailed Explanation of Message Queues
FreeRTOS Learning – Counting Semaphores
FreeRTOS Learning – Mutex Semaphores
FreeRTOS Learning – Event Groups
FreeRTOS Learning – Task Notifications
FreeRTOS Learning – Software Timers
This article introduces the memory management related content of FreeRTOS.
FreeRTOS provides a flexible memory management mechanism that allows developers to choose the most suitable memory allocation strategy based on different application scenarios and hardware resources.
Memory management in FreeRTOS has the following characteristics:
- Portability: The memory management interface is separated from the specific implementation
- Customizability: Provides multiple memory management algorithms and supports user-defined implementations
- Determinism: Some implementations provide deterministic allocation times
- Fragmentation Control: Provides strategies to reduce memory fragmentation
Memory Management Architecture
Memory Management Hierarchy
FreeRTOS memory management is divided into three levels:
- Hardware-Dependent Layer: Handles memory layout specific to the MCU and memory initialization at startup
- Kernel Memory Management Layer: Memory allocation for FreeRTOS kernel objects (tasks, queues, semaphores, etc.)
- Application Memory Management Layer: Memory allocation for user applications
Memory Management Interface
FreeRTOS defines a unified memory management interface (in portable.h):
void *pvPortMalloc(size_t xSize);
void vPortFree(void *pv);
size_t xPortGetFreeHeapSize(void);
size_t xPortGetMinimumEverFreeHeapSize(void);
Five Memory Management Implementations
FreeRTOS source code provides five memory management implementations, located in the <span>FreeRTOS/Source/portable/MemMang</span> directory:
heap_1.c – The Simplest Implementation
Characteristics:
- Only allocates, does not free
- Deterministic execution time
- Small code size
Implementation Principle:
- Simply divides memory into a static array
- Uses a pointer to track remaining space
Applicable Scenarios:
- Applications that only allocate memory at startup and do not free it afterwards
- Systems with high determinism requirements
API Behavior:
<span>pvPortMalloc()</span>: Works normally<span>vPortFree()</span>: Does not perform any operation (empty function)
heap_2.c – Best Fit Algorithm
Characteristics:
- Supports allocation and deallocation
- Uses the best fit algorithm
- Does not merge adjacent free blocks
Implementation Principle:
- Divides the heap into a block linked list
- Each block contains metadata and user data area
- Finds the closest free block to the requested size during allocation
Disadvantages:
- Can produce memory fragmentation
- Allocation time is not deterministic
Applicable Scenarios:
- Applications that require dynamic allocation and deallocation, but with relatively fixed allocation sizes
- Has gradually been replaced by heap_4.c
heap_3.c – Standard Library Wrapper
Characteristics:
- Wraps the standard library’s malloc() and free()
- Adds thread safety protection
Implementation Principle:
- Protects malloc/free operations with mutex locks
- Directly calls the malloc/free provided by the compiler
Applicable Scenarios:
- Platforms with mature standard library implementations
- Need to integrate with other code using the standard library
heap_4.c – First Fit Algorithm with Fragmentation Merging
Characteristics:
- Supports allocation and deallocation
- Uses the first fit algorithm
- Merges adjacent free blocks to reduce fragmentation
- Deterministic execution time (if using the same size allocation)
Implementation Principle:
- Maintains a linked list of free blocks sorted by address
- Uses the first fit algorithm during allocation
- Checks and merges adjacent free blocks during deallocation
Advantages:
- Effectively reduces memory fragmentation
- Higher allocation efficiency
Applicable Scenarios:
- Applications that require frequent dynamic allocation of different sized memory
- Recommended choice for most general applications
heap_5.c – Supports Non-contiguous Memory Regions
Characteristics:
- Has all the features of heap_4
- Supports multiple non-contiguous memory regions
- Requires explicit initialization of memory regions
Implementation Principle:
- Uses the algorithm of heap_4
- Maintains information about multiple memory regions
Applicable Scenarios:
- Hardware with memory distributed across multiple non-contiguous regions
- Need to manage different types of memory (e.g., fast RAM and slow RAM) uniformly
Configuration and Usage
Configuring FreeRTOS Memory Management
Configure in FreeRTOSConfig.h:
#define configTOTAL_HEAP_SIZE ((size_t)1024*25) // Define total heap size
#define configAPPLICATION_ALLOCATED_HEAP 0 // Heap memory allocated by the compiler (1 means user allocated)
#define configUSE_MALLOC_FAILED_HOOK 0 // Whether to enable malloc failure hook function
Selecting Memory Management Implementation
Include the corresponding memory management source file in the project (e.g., heap_4.c)
Custom Memory Management
Developers can fully customize memory management:
- Implement pvPortMalloc() and vPortFree()
- Optionally implement xPortGetFreeHeapSize() and other auxiliary functions
- Set in FreeRTOSConfig.h:
#define configAPPLICATION_ALLOCATED_HEAP 1
extern uint8_t ucHeap[configTOTAL_HEAP_SIZE]; // User-defined heap memory
Usage Recommendations
Heap Size Planning
Monitor heap usage:
printf("Free heap: %u, Min ever free: %u\n",
xPortGetFreeHeapSize(),
xPortGetMinimumEverFreeHeapSize());
Consider:
- All task stack space
- Kernel objects (queues, semaphores, etc.) usage
- Application dynamic memory requirements
- Reserve a safety margin (usually 20-30%)
Strategies to Reduce Memory Fragmentation
Try to use static allocation:
StaticTask_t xTaskBuffer;
StackType_t xStack[configMINIMAL_STACK_SIZE];
xTaskCreateStatic(...);
- Uniformly allocate sizes or use memory pools
- Avoid frequent allocation/deallocation of different sized memory blocks
Debugging Tips
Enable malloc failure hook:
void vApplicationMallocFailedHook(void) {
// Handle memory allocation failure
}
Use FreeRTOS built-in memory statistics feature:
#define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
Regularly check heap usage
Advanced
Memory Protection (MPU) Support
For ARM Cortex-M processors with MPU:
#define configENABLE_MPU 1
#define configTOTAL_MPU_REGIONS 8
Thread Local Storage (TLS)
FreeRTOS supports task-specific memory pointers:
void *pvTaskGetThreadLocalStoragePointer(TaskHandle_t xTask, BaseType_t xIndex);
void vTaskSetThreadLocalStoragePointer(TaskHandle_t xTask, BaseType_t xIndex, void *pvValue);
Stack Overflow Detection
Method 1: Stack Filling Mode Detection
#define configCHECK_FOR_STACK_OVERFLOW 1
Method 2: MPU Protection Detection
#define configCHECK_FOR_STACK_OVERFLOW 2
Common Issues and Solutions
Memory Allocation Failure
Possible Causes:
- Insufficient heap size
- Severe memory fragmentation
- Memory leaks
Solutions:
- Increase configTOTAL_HEAP_SIZE
- Switch to a more efficient memory management algorithm
- Check and fix memory leaks
Memory Leaks
Detection Methods:
- Regularly check xPortGetFreeHeapSize()
- Use professional memory analysis tools
- Implement memory tracking wrappers
Preventive Measures:
- Establish ownership rules for each allocation
- Use RAII pattern (Resource Acquisition Is Initialization)
- Establish clear memory release responsibilities
Performance Issues
Optimization Strategies:
- For frequently allocated small objects, use memory pools
- Consider static allocation of critical objects
- Select appropriate memory management algorithms
Application Examples
Custom Memory Management Implementation
#define CUSTOM_HEAP_SIZE (1024 * 32)
static uint8_t ucCustomHeap[CUSTOM_HEAP_SIZE];
static size_t xNextFreeByte = 0;
void *pvPortMalloc(size_t xWantedSize)
{
void *pvReturn = NULL;
if((xNextFreeByte + xWantedSize) < CUSTOM_HEAP_SIZE)
{
pvReturn = &ucCustomHeap[xNextFreeByte];
xNextFreeByte += xWantedSize;
}
return pvReturn;
}
void vPortFree(void *pv)
{
// Simple implementation does not support freeing
}
Memory Pool Implementation
#define POOL_BLOCK_SIZE 32
#define POOL_BLOCKS 100
typedef struct
{
uint8_t ucBlock[POOL_BLOCK_SIZE];
BaseType_t xInUse;
} MemoryBlock_t;
static MemoryBlock_t xMemoryPool[POOL_BLOCKS];
void *pvGetMemoryBlock(void)
{
for(int i = 0; i < POOL_BLOCKS; i++)
{
if(!xMemoryPool[i].xInUse)
{
xMemoryPool[i].xInUse = pdTRUE;
return xMemoryPool[i].ucBlock;
}
}
return NULL;
}
void vReturnMemoryBlock(void *pv)
{
for(int i = 0; i < POOL_BLOCKS; i++)
{
if(xMemoryPool[i].ucBlock == pv)
{
xMemoryPool[i].xInUse = pdFALSE;
break;
}
}
}
Optimization
- Allocation Time Analysis:
- heap_1 and heap_4 have deterministic times for the same size allocation
- heap_2 and heap_5 have non-deterministic times
- heap_1: No management overhead
- heap_2/heap_4: About 8-16 bytes of metadata per block
- heap_5: Additional region management overhead
- Reduce the number of dynamic memory allocations
- Use static allocation for critical resources
- Avoid memory operations in low power modes
Conclusion
FreeRTOS provides a flexible and diverse memory management solution, allowing developers to choose the most suitable implementation based on application needs.
For most application scenarios, heap_4.c is the recommended default choice, offering good performance and fragmentation control capabilities.
In resource-constrained or special requirement systems, other implementations or custom memory management can be considered.
Key Recommendations:
- Fully understand the memory usage patterns of the application
- Closely monitor memory usage during the development phase
- Reserve sufficient memory margin for production systems
- Consider using static allocation to improve system determinism
- Establish strict memory management standards to prevent memory leaks and fragmentation issues

Follow 【Learn Embedded Together】 to become better together.
If you find this article useful, click “Share”, “Like”, or “Recommend”!