FreeRTOS study notes (9)-memory management

1. Basic concepts

The FreeRTOS operating system separates the kernel and memory management. The operating system kernel only specifies the necessary memory management function prototypes, and does not care how these memory management functions are implemented. Therefore, FreeRTOS provides a variety of memory allocation algorithms (allocation strategies). ), but the upper-level interface (API) is unified. Doing so can increase the flexibility of the system: users can choose a more advantageous memory management strategy, and use different memory allocation strategies in different applications.

In embedded programming, memory allocation should be based on the characteristics of the designed system to decide whether to use dynamic memory allocation or static memory allocation algorithms. Some systems with very high reliability requirements should choose to use static ones, while ordinary business systems can be used. Dynamically improve memory usage efficiency. Static can ensure the reliability of the device, but the upper limit of memory needs to be considered, memory usage efficiency is low, and dynamic is the opposite.

Whenever a task, queue or semaphore is created, the kernel needs to perform dynamic memory allocation. Although you can call the standard malloc() and free() library functions, you must bear the following issues:

  1. These two functions may not be available in small embedded systems, and there is insufficient RAM in small embedded devices.
  2. The specific implementation of these two functions may be relatively large and will occupy more valuable code space.
  3. These two functions usually do not have thread safety features.
  4. These two functions are uncertain. The time overhead of each call may be different.
  5. These two functions will generate memory fragmentation.
  6. These two functions will complicate the configuration of the linker.

FreeRTOS has done a lot of memory management. The V9.0.0 version of FreeRTOS provides us with 5 memory management algorithms, namely heap_1.c, heap_2.c, heap_3.c, heap_4.c, heap_5.c , and the source files are stored. in \ Source \ portable FreeRTOS \ MemMang of the path, choose which one to use when added to our project can go.

The memory management module of FreeRTOS manages the use of memory by users and the system through memory application and release operations, so as to optimize the utilization and efficiency of the memory, and to solve the problem of memory fragmentation that may occur in the system to the greatest extent.

Two, memory management scheme

2.1 heap_1.c

The heap_1.c management scheme is the simplest of all the memory management schemes provided by FreeRTOS. It can only apply for memory but not for memory release, and the time to apply for memory is a constant , which is suitable for embedded devices that require security The best, because memory is not allowed to release, there will be no memory fragmentation and cause system crashes, but there are also disadvantages, that is, the memory utilization is not high, a certain section of memory can only be used for memory applications, even if the memory is only used Once, the system cannot be recycled and reused.

In fact, most embedded systems do not always dynamically apply for and release memory. Generally, when the system is completed, it will be used forever and never deleted. Therefore, this memory management solution is simple, safe and reliable. Very extensive.

Required when the total heap memory allocation space by the file FreeRTOSConfig.hin a macro ·configTOTAL_HEAP_SIZEconfiguration, the unit is the word. By calling the function xPortGetFreeHeapSize() we can know how much memory is left unused, but it does not include memory fragmentation. In this way we can real-time adjustment and optimization configTOTAL_HEAP_SIZEof size.

heap_1.c implements a very basic version of pvPortMalloc() and does not implement vPortFree().

The heap1.c solution has the following characteristics:

  • Used for applications that never delete tasks, queues, semaphores, mutexes, etc. (in fact, most applications that use FreeRTOS meet this condition).
  • The execution time of the function is determined and there is no memory fragmentation.

2.2 heap_2.c

The memory management algorithm used in the heap_2.c solution is different from the heap_1.c solution. It uses a best fit algorithm . For example, we apply for 100 bytes of memory, and there are three blocks in the available memory that correspond to the size of 200. Byte, 500-byte and 1000-byte memory blocks, according to the best match of the algorithm, at this time the system will divide the 200-byte memory block and return the starting address of the requested memory, and the remaining memory will be inserted The linked list is reserved for the next application. The heap_2.c solution supports the release of the requested memory, but it cannot combine two adjacent small memory blocks into one large memory block. For each application for a relatively fixed memory size, this method is no problem. Each application that is not a fixed memory size will cause memory fragmentation. The memory management algorithm used in the heap_4.c solution to be explained later can solve the problem of memory fragmentation. These released adjacent small memory blocks can be merged into one Large memory block.

Similarly, the required memory allocation when the total heap memory space by the file FreeRTOSConfig.hin a macro configTOTAL_HEAP_SIZEconfiguration, the unit is the word. By calling the function xPortGetFreeHeapSize () we can not know how much memory is left to use, but does not include memory fragmentation, so that we can adjust and optimize in real time configTOTAL_HEAP_SIZEthe size.

The heap_2.c solution has the following characteristics:

  • It can be used in applications that repeatedly delete tasks, queues, semaphores, and other kernel objects without worrying about memory fragmentation.
  • If the queues, tasks, semaphores, etc. in our application work in an unpredictable order, this may also cause memory fragmentation.
  • There is uncertainty, but the efficiency is much higher than the malloc function in the standard C library.
  • It cannot be used for applications whose memory allocation and release are of random size.

2.3 heap_3.c

The heap_3.c solution simply encapsulates the malloc() and free() functions in the standard C library , and can satisfy commonly used compilers. The malloc() and free() functions after re-encapsulation have protection functions. The encapsulation method adopted is to suspend the scheduler before operating the memory, and then resume the scheduler after completion.

The heap_3.c solution has the following characteristics:

  • The linker needs to set up a heap, and the malloc() and free() functions are provided by the compiler.
  • There is uncertainty.
  • It is possible to increase the code size of the RTOS kernel.

Note that when using heap_3.c program, FreeRTOSConfig.h file configTOTAL_HEAP_SIZEmacros do not work. In the STM32 series project, the heap defined by the compiler is set in the startup file, and the unit is byte. Let's take the STM32F10x series as an example.

2.4 heap_4.c

The heap_4.c scheme and the heap_2.c scheme both use the best matching algorithm to achieve dynamic memory allocation , but the difference is that the heap_4.c scheme also includes a merge algorithm that can merge adjacent free memory blocks Into a larger block, this can reduce memory fragmentation . The heap_4.c scheme is especially suitable for codes that can directly use the pvPortMalloc() and vPortFree() functions to allocate and release memory in the transplantation layer.

Required when the total heap memory allocation space by the file FreeRTOSConfig.hin a macro ·configTOTAL_HEAP_SIZEconfiguration, the unit is the word. By calling the function xPortGetFreeHeapSize() we can know how much memory is left unused, but it does not include memory fragmentation. In this way we can real-time adjustment and optimization configTOTAL_HEAP_SIZEof size.

The free memory blocks of the heap_4.c solution are also connected in the form of a singly linked list. The local static variable xStart of the BlockLink_t type represents the head of the linked list, but the end of the linked list of the heap_4.c memory management scheme is stored in the last position of the memory heap space and used The blockLink_t pointer type local static variable pxEnd points to this area (and the heap_2.c memory management solution uses the BlockLink_t type static variable xEnd to represent the end of the linked list)

The free block list of the heap_4.c memory management solution is not sorted by the size of the memory block, but sorted by the size of the starting address of the memory block. The smaller memory address is first, and the larger address is last, because the heap_4.c solution also has A memory merging algorithm, when releasing memory, if two adjacent free memory blocks are consecutive in address, then they can be merged into one memory block, which is also a change to adapt to the merge algorithm.

The heap_4.c solution has the following characteristics:

  • Can be used for applications that repeatedly delete tasks, queues, semaphores, mutexes, etc.
  • It can be used for applications that allocate and release random bytes of memory, but it does not produce serious memory fragmentation like heap2.c.
  • There is uncertainty, but the efficiency is much higher than the malloc function in the standard C library.

2.5 heap_5.c

The heap_5.c solution is the same as the heap4.c solution when implementing dynamic memory allocation. It uses the best matching algorithm and merge algorithm, and allows the memory heap to span multiple non-contiguous memory areas, that is, it allows the implementation in the non-contiguous memory heap Memory allocation, for example, the user defines a memory heap in the on-chip RAM, and can also define one or more memory heaps in the external SDRAM. These memories are managed by the system.

The heap_5.c solution implements system-managed memory initialization by calling the vPortDefineHeapRegions() function. Memory allocation and release functions are not allowed before the memory initialization is completed. For example, when creating FreeRTOS objects (tasks, queues, semaphores, etc.), the pvPortMalloc() function is implicitly called. Therefore, you must pay attention: before you create any objects using the heap_5.c memory management scheme, you must first call the vPortDefineHeapRegions() function to initialize the memory .

The heap_5.c solution has the following characteristics:

  • Can be used for applications that repeatedly delete tasks, queues, semaphores, mutexes, etc.
  • It can be used for applications that allocate and release random bytes of memory, but it does not produce serious memory fragmentation like heap2.c.
  • There is uncertainty, but the efficiency is much higher than the malloc function in the standard C library.
  • Allow the memory heap to span multiple non-contiguous memory areas, that is, allow memory allocation in the non-contiguous memory heap.

Three, memory management interface function

3.1 pvPortMalloc

void *pvPortMalloc( size_t xSize )
This function is a memory allocation function specified by FreeRTOS. If the internal system and users want to use memory, they can only apply through this function interface.

3.2 vPortFree

void vPortFree( void *pv )
This function is a memory release function specified by FreeRTOS. If the internal system and users want to release the memory, they can only apply through this function interface.在heap_1.c方案,内存一旦申请便无法释放!

3.3 vPortInitialiseBlocks

void vPortInitialiseBlocks( void )
This function is a memory management initialization function specified by FreeRTOS.

3.4 xPortGetFreeHeapSize

size_t xPortGetFreeHeapSize( void )
This function is defined by FreeRTOS to obtain the remaining size of dynamic memory. The only thing to note is that its size is after alignment!

3.5 xPortGetMinimumEverFreeHeapSize

size_t xPortGetMinimumEverFreeHeapSize( void )
Get the historical minimum value of unallocated memory heap.

Four, example

uint8_t *Test_Ptr = NULL;

/* 获取当前内存大小 */ 
g_memsize = xPortGetFreeHeapSize(); 
printf("系统当前内存大小为 %d 字节,开始申请内存\n",g_memsize); 
Test_Ptr = pvPortMalloc(1024); // 申请内存
if (NULL != Test_Ptr) 
{
    
     
    printf("内存申请成功!\n"); 
    printf("申请到的内存地址为%#x\n",(int)Test_Ptr);
}

vPortFree(Test_Ptr); // 释放内存 
Test_Ptr = NULL; 
/* 获取当前内剩余存大小 */ 
g_memsize = xPortGetFreeHeapSize(); 
printf("系统当前内存大小为 %d 字节,内存释放完成\n",g_memsize);

Written by Leung on December 28, 2020

• Reference: Wildfire FreeRTOS video and PDF tutorial

Guess you like

Origin blog.csdn.net/qq_36347513/article/details/111869301