4.4.7.1 Dynamic Memory Allocation for AVR Devices

The MPLAB XC8 C Compiler implements a unrestricted dynamic memory allocation scheme for all target devices; however, the smaller devices, such at tinyAVR devices, are unlikely to have enough program memory to accommodate the required library functions, nor have enough data memory to allow dynamic memory allocation to be useful.

The dynamic memory allocation scheme permits the use of all the standard memory allocation library functions. Initially, memory can be allocated as required, subject only to the maximum size reserved for the heap. Memory blocks that are freed after allocation are coalesced with neighboring free memory and grouped into bins of similar sizes. This memory will be considered for re-allocation whenever additional memory is subsequently requested.

Although the allocation scheme attempts to utilize memory efficiently, fragmentation can always occur. Use caution when allocating and freeing memory. Prudent program designers will avoid using dynamic memory allocation, if at all possible.

Although successful calls to memory allocation functions will return a block with sufficient size to store the requested number of bytes, the total size of each allocated block may be larger than the requested size, and that size is dependent on whether the free() function is called in the program.

If free() is never called, then the memory allocation functions allocate a block with the requested memory size if possible and a pointer to that block returned. A request to allocate 1 byte of memory, such as malloc(1), will in this case allocate a 1-byte block, provided enough free memory exists.

If free() is called in the program, then the compiler will include additional memory with each block allocated to manage the memory. In this case, each allocated block will include a 2-byte-wide header and an additional 2 bytes will be used as a free list pointer and thus, the minimum amount of memory that can be allocated for a block is 4 bytes. As the 2 bytes located before the memory whose address is returned after a successful allocation contain the header information, your program should never assume that this memory might contain allocated user data.

Regardless of whether the free() function is called, a request to allocate zero bytes of memory, such as malloc(0), will be treated like a request to allocate 1 byte of memory, and if successful, will return a pointer to the memory allocated.

There are a number of variables that can be tuned to customize the behavior of the allocation functions, such as malloc(). Any changes to these variables should be made before any memory allocation is made, remembering that any library functions called might use dynamic memory.

The variables __malloc_heap_start and __malloc_heap_end can be used to restrict the memory allocated by the malloc() and calloc() functions. These variables are statically initialized to point to __heap_start and __heap_end, respectively. The __heap_start variable is set to an address just beyond the last data memory address used by Best Fit Allocator after the allocation of static objects, and __heap_end is set to 0, which places the heap below the stack.

If the heap is located in external RAM, __malloc_heap_end must be adjusted accordingly. This can be done either at run-time, by writing directly to this variable, or it can be done automatically at link-time, by adjusting the value of the symbol __heap_end.

The following example shows an option that can relocate those input sections mapped to the .data output section in the linker script to location 0x1100 in external RAM. Since these are addresses in RAM, the MSb is set in the specified addresses. The heap will extend up to address 0xffff.
-Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff
If the heap should be located in external RAM while keeping the ordinary variables in internal RAM, the following options can be used. Note that in this example, there is a ’hole’ in memory between the heap and the stack that remains inaccessible by ordinary variables or dynamic memory allocations.
-Wl,--defsym=__heap_start=0x802000,--defsym=__heap_end=0x803fff

If __malloc_heap_end is 0, the memory allocation routines attempt to detect the bottom of the stack in order to prevent a stack-heap collision when extending the heap. They will not allocate memory beyond the current stack limit with a buffer of __malloc_margin bytes. Thus, all possible stack frames of interrupt routines that could interrupt the current function, plus all further nested function calls must not require more stack space, or they will risk colliding with the data segment. The default value of __malloc_margin is set to 32.