Guide to Dynamic Memory Usage in FreeRTOS: Choosing Between malloc and pvPortMalloc

In embedded development, you might write something like this:

uint8_t* buf = malloc(1024); // Allocate 1KB of memory

It seems convenient, but in a multitasking system like FreeRTOS, there are some details regarding memory management that need attention.

Differences Between malloc Heap and FreeRTOS Heap

Feature malloc / free pvPortMalloc / vPortFree
Heap Source C Library heap FreeRTOS heap_4
Thread Safety Potentially unsafe Thread safe
Managed Objects Own dynamic memory Task stacks, queues, semaphores, dynamic objects
Memory Control Separate from RTOS heap Unified system management

💡 Key Point:

  • <span>malloc</span> / <span>free</span> allocate from the C library managed heap, typically in the <span>.heap</span> section of the linker script or high address RAM.

    • This portion of memory is not directly associated with FreeRTOS task stacks and queues.

    • In a multitasking environment, the thread safety of C library malloc/free depends on the compiler/library implementation, and some libraries may be unsafe in multitasking.

  • <span>pvPortMalloc</span> / <span>vPortFree</span> allocate from the FreeRTOS heap (heap_4, etc.), typically reserving a static array in STM32’s RAM:

#define configTOTAL_HEAP_SIZE  (46 * 1024) // 46 KB
static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
  • All task stacks, TCBs, dynamic queues, semaphores, and dynamic objects mapped using <span>pvPortMalloc</span> / LVGL are allocated from this RAM.

  • Thread safe, with unified management in a multitasking environment, avoiding memory fragmentation and cross-task access issues.

In simple terms: on STM32, <span>malloc</span> is the “system heap”, while <span>pvPortMalloc</span> is the “RTOS heap”; the two heaps do not interfere with each other in RAM, but the FreeRTOS heap is more suitable for multitasking and GUI systems.

FreeRTOS provides various heap implementations, with heap_4 being the most commonly used:

Features of heap_4:

  • Task stacks, TCBs, queues, and semaphores can all be allocated from this heap

  • Supports dynamic release and merging of free blocks

  • Compatible with thread safety in multitasking

Dynamic Memory in LVGL

If you are using LVGL in a GUI system, you can also allocate memory through the FreeRTOS heap:

#define LV_MEM_CUSTOM_ALLOC pvPortMalloc
#define LV_MEM_CUSTOM_FREE   vPortFree
void* buf = lv_mem_alloc(512); // Dynamically allocate
lv_mem_free(buf);              // Release when done
  • Dynamic objects like LVGL controls and labels use the same heap, ensuring unified management

  • Avoid stack overflow or fragmented RAM

For large buffers (e.g., 240×240 double buffering), it is recommended to place them in a global array or Flash to save heap space.

Principles of Dynamic Memory Allocation

  1. Small objects can be dynamically allocated

  • Both <span>pvPortMalloc</span> and <span>lv_mem_alloc</span> are thread safe.

  • Large buffers should be statically allocated or placed in Flash

    • Avoid heap fragmentation and stack overflow.

  • Task stack sizes should be reasonable

    • GUI tasks ≥ 2 KB, regular tasks can be smaller.

  • Check allocation return values

    • Have handling logic for NULL to prevent system exceptions.

    Example: Dynamic Memory Allocation in GUI Task

    void gui_task(void *arg) {
        uint8_t* temp_buf = lv_mem_alloc(512); // Allocate temporary buffer
        if(temp_buf == NULL) {
            printf("Insufficient memory!\n");
            vTaskDelay(pdMS_TO_TICKS(1000));
            return;
        }
        while(1) {
            update_gui(temp_buf); // Draw interface
            lv_task_handler();
            vTaskDelay(pdMS_TO_TICKS(10));
        }
        lv_mem_free(temp_buf);
    }
    
    • The temporary buffer is safely used within the task, not occupying global RAM.

    • Using LVGL’s memory mapped to the FreeRTOS heap allows for unified management.

    Conclusion

    • malloc allocates from the C library heap, while pvPortMalloc allocates from the FreeRTOS heap, which is thread safe and managed alongside task stacks and queues.

    • It is best to map LVGL dynamic objects to the FreeRTOS heap, while drawing buffers should be statically allocated or placed in Flash.

    • For dynamic memory allocation, use the heap for small blocks, statically allocate large buffers, and ensure reasonable total RAM usage for higher system stability.

    Leave a Comment