The terms "internal" and "external" in the context of fragmentation refer to the location of the unused or wasted memory in relation to the allocated memory blocks. Let's break down the reasons behind these names:
Internal Fragmentation:
-
Location: Internal fragmentation describes the situation where memory is wasted within the allocated memory blocks.
-
Reason for "Internal": The wasted space is internal to the allocated block. It's space that is part of the allocated block but is not utilized by the data or processes residing in that block.
-
Example: If a process is allocated a memory block that is larger than it actually needs, the unused portion within that block is considered internal fragmentation.
External Fragmentation:
-
Location: External fragmentation describes the situation where free memory is scattered throughout the system but is not contiguous.
-
Reason for "External": The wasted space is external to the allocated blocks. It refers to the fragmentation in the free memory space outside the allocated blocks.
-
Example: When free memory is scattered in small, non-contiguous chunks between allocated blocks, making it challenging to find a single large contiguous block for a new allocation, it is considered external fragmentation.
Distinction:
The distinction between internal and external fragmentation is based on where the wasted space is located with respect to the memory blocks:
- Internal Fragmentation: Wasted space is inside the allocated blocks.
- External Fragmentation: Wasted space is outside the allocated blocks, scattered in non-contiguous regions.
These terms help in identifying and addressing specific types of memory inefficiencies. Internal and external fragmentation are challenges that memory management strategies aim to mitigate, ensuring efficient use of available memory resources in a computer system.
FreeROS 5 heap implementations
Each created task requires a task control block (TCB) and a stack to be allocated from the heap.
- heap_1: Heap_1.c implements a very basic version of pvPortMalloc(), and does not implement vPortFree(). Applications that never delete a task, or other kernel object, have the potential to use heap_1.
- heap_2: also works by subdividing an array that is dimensioned by configTOTAL_HEAP_SIZE. It uses a best fit algorithm to allocate memory and, unlike heap_1, it does allow memmory to be freed. Again, the arry is statically declared, so will make the application appear to consume a lot of RAM, even before any memory from the array has been assigned. The best fit algorithm ensures that pvPortMalloc() uses the free block of memory that is closest in size to the number of bytes requested. Unlike heap_4, Heap_2 does not combine adjacent free blocks into a single larger block, so it is more susceptible to fragmentation. However, fragementation is not an issue if the blocks being allocated and subsequently freed are always the same size. Heap_2 is suitable for an application that creates and deletes tasks repeatly, provided the size of the stack allocated to the created tasks does not change.
- A shows the array after three tasks have been created. A large free block remains at the top of the array.
- B shows the array after one of the tasks has been deleted. The large free block at the top of the array remains. There are now also two smaller free blocks that were previously allocated to the TCB and stack of the deleted task.
- C shows the situation after another task has been created. Creating the task has resulted in two calls to pvPortMalloc(), one to allocate a new TCB, and one to allocate the task stack. Tasks are created using the xTaskCreate() API function. The calles pvPortMalloc() occur internally within xTaskCreate(). The larger unallocated block at the top of the array remains untouched.
- heap_3: Heap_3.c uses the standard library malloc() and free() functions, so the size of the heap is defined by the linker configuration, and the configTOTAL_HEAP_SIZE setting has no affect. Heap_3 makes malloc() and free() thread-safe by temporarily suspending the FreeRTOS scheduler.
- heap_4: Like heap_1 and heap_2, heap_4 works by subdividing an array into smaller blocks. As before, the array is statically declared, and dimensioned by configTOTAL_HEAP_SIZE, so will make the application appear to consume a lot of RAM, even before any memory has actually been allocated from the array. Heap_4 uses a first fit algorithm to allocate memroy. Unlike heap_2, heap_4 combines adjacent free blocks of memory into as single larger block, which minimizes the risk of memory fragmentation. Heap_4 combines (coalescences) adjacent free blocks into a single larger block, minimizing the risk of fragmentaion, and making it suitable for applications that repeatedly allocated and free different sized blocks of RAM. Heap_4 is not deterministic, but is faster than most standard library implementations of malloc() and free().
- heap_5: The algorithm used by heap_5 to allocate and free memory is identical to that used by heap_4. Unlike heap_4, heap_5 is not limited to allocating memory from a single statically declared array; heap_5 can allocate memory from multiple and separated memory spaces. Heap_5 is useful when the RAM provided by the system on which FreeRTOS is running does not appear as a single contiguous (without space) block in the system's memory map. Heap_5 is the only provided memory allocation scheme that must be explicitly intialized before pvPortMalloc() can be called. Heap_5 is initialized using the vPortDefineHeapRegions() API function. When heap_5 is used, vPortDefineHeapRegions() must be called before any kernel objects (tasks, queues, semaphores, etc.) can be created.