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
.
.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
-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.