Memory Heaps¶
Zephyr provides a collection of utilities that allow threads to dynamically allocate memory.
Synchronized Heap Allocator¶
Creating a Heap¶
The simplest way to define a heap is statically, with the
K_HEAP_DEFINE
macro. This creates a static k_heap
variable
with a given name that manages a memory region of the
specified size.
Heaps can also be created to manage arbitrary regions of
application-controlled memory using k_heap_init()
.
Allocating Memory¶
Memory can be allocated from a heap using k_heap_alloc()
,
passing it the address of the heap object and the number of bytes
desired. This functions similarly to standard C malloc()
,
returning a NULL pointer on an allocation failure.
The heap supports blocking operation, allowing threads to go to sleep
until memory is available. The final argument is a
k_timeout_t
timeout value indicating how long the thread may
sleep before returning, or else one of the constant timeout values
K_NO_WAIT
or K_FOREVER
.
Releasing Memory¶
Memory allocated with k_heap_alloc()
must be released using
k_heap_free()
. Similar to standard C free()
, the pointer
provided must be either a NULL
value or a pointer previously
returned by k_heap_alloc()
for the same heap. Freeing a
NULL
value is defined to have no effect.
Low Level Heap Allocator¶
The underlying implementation of the k_heap
abstraction is provided a data structure named sys_heap
. This
implements exactly the same allocation semantics, but
provides no kernel synchronization tools. It is available for
applications that want to manage their own blocks of memory in
contexts (for example, userspace) where synchronization is unavailable
or more complicated. Unlike k_heap
, all calls to any sys_heap
functions on a single heap must be serialized by the caller.
Simultaneous use from separate threads is disallowed.
Implementation¶
Internally, the sys_heap
memory block is partitioned into “chunks”
of 8 bytes. All allocations are made out of a contiguous region of
chunks. The first chunk of every allocation or unused block is
prefixed by a chunk header that stores the length of the chunk, the
length of the next lower (“left”) chunk in physical memory, a bit
indicating whether the chunk is in use, and chunk-indexed link
pointers to the previous and next chunk in a “free list” to which
unused chunks are added.
The heap code takes reasonable care to avoid fragmentation. Free block lists are stored in “buckets” by their size, each bucket storing blocks within one power of two (i.e. a bucket for blocks of 3-4 chunks, another for 5-8, 9-16, etc…) this allows new allocations to be made from the smallest/most-fragmented blocks available. Also, as allocations are freed and added to the heap, they are automatically combined with adjacent free blocks to prevent fragmentation.
All metadata is stored at the beginning of the contiguous block of
heap memory, including the variable-length list of bucket list heads
(which depend on heap size). The only external memory required is the
sys_heap
structure itself.
The sys_heap
functions are unsynchronized. Care must be taken by
any users to prevent concurrent access. Only one context may be
inside one of the API functions at a time.
The heap code takes care to present high performance and reliable
latency. All sys_heap
API functions are guaranteed to complete
within constant time. On typical architectures, they will all
complete within 1-200 cycles. One complexity is that the search of
the minimum bucket size for an allocation (the set of free blocks that
“might fit”) has a compile-time upper bound of iterations to prevent
unbounded list searches, at the expense of some fragmentation
resistance. This CONFIG_SYS_HEAP_ALLOC_LOOPS
value may be
chosen by the user at build time, and defaults to a value of 3.
System Heap¶
The system heap is a predefined memory allocator that allows
threads to dynamically allocate memory from a common memory region in
a malloc()
-like manner.
Only a single system heap is defined. Unlike other heaps or memory pools, the system heap cannot be directly referenced using its memory address.
The size of the system heap is configurable to arbitrary sizes, subject to space availability.
A thread can dynamically allocate a chunk of heap memory by calling
k_malloc()
. The address of the allocated chunk is
guaranteed to be aligned on a multiple of pointer sizes. If a suitable
chunk of heap memory cannot be found NULL
is returned.
When the thread is finished with a chunk of heap memory it can release
the chunk back to the system heap by calling k_free()
.
Defining the Heap Memory Pool¶
The size of the heap memory pool is specified using the
CONFIG_HEAP_MEM_POOL_SIZE
configuration option.
By default, the heap memory pool size is zero bytes. This value instructs the kernel not to define the heap memory pool object. The maximum size is limited by the amount of available memory in the system. The project build will fail in the link stage if the size specified can not be supported.
Allocating Memory¶
A chunk of heap memory is allocated by calling k_malloc()
.
The following code allocates a 200 byte chunk of heap memory, then fills it with zeros. A warning is issued if a suitable chunk is not obtained.
char *mem_ptr;
mem_ptr = k_malloc(200);
if (mem_ptr != NULL)) {
memset(mem_ptr, 0, 200);
...
} else {
printf("Memory not allocated");
}
Releasing Memory¶
A chunk of heap memory is released by calling k_free()
.
The following code allocates a 75 byte chunk of memory, then releases it once it is no longer needed.
char *mem_ptr;
mem_ptr = k_malloc(75);
... /* use memory block */
k_free(mem_ptr);
Suggested Uses¶
Use the heap memory pool to dynamically allocate memory in a
malloc()
-like manner.
API Reference¶
-
group
heap_apis
Defines
-
K_HEAP_DEFINE
(name, bytes)¶ Define a static k_heap.
This macro defines and initializes a static memory region and k_heap of the requested size. After kernel start, &name can be used as if k_heap_init() had been called.
- Parameters
name
: Symbol name for the struct k_heap objectbytes
: Size of memory region, in bytes
Functions
-
void
k_heap_init
(struct k_heap *h, void *mem, size_t bytes)¶ Initialize a k_heap.
This constructs a synchronized k_heap object over a memory region specified by the user. Note that while any alignment and size can be passed as valid parameters, internal alignment restrictions inside the inner sys_heap mean that not all bytes may be usable as allocated memory.
- Parameters
h
: Heap struct to initializemem
: Pointer to memory.bytes
: Size of memory region, in bytes
-
void *
k_heap_aligned_alloc
(struct k_heap *h, size_t align, size_t bytes, k_timeout_t timeout)¶ Allocate aligned memory from a k_heap.
Behaves in all ways like k_heap_alloc(), except that the returned memory (if available) will have a starting address in memory which is a multiple of the specified power-of-two alignment value in bytes. The resulting memory can be returned to the heap using k_heap_free().
- Note
Can be called by ISRs, but timeout must be set to K_NO_WAIT.
- Return
Pointer to memory the caller can now use
- Parameters
h
: Heap from which to allocatealign
: Alignment in bytes, must be a power of twobytes
: Number of bytes requestedtimeout
: How long to wait, or K_NO_WAIT
-
static inline void *
k_heap_alloc
(struct k_heap *h, size_t bytes, k_timeout_t timeout)¶ Allocate memory from a k_heap.
Allocates and returns a memory buffer from the memory region owned by the heap. If no memory is available immediately, the call will block for the specified timeout (constructed via the standard timeout API, or K_NO_WAIT or K_FOREVER) waiting for memory to be freed. If the allocation cannot be performed by the expiration of the timeout, NULL will be returned.
- Note
Can be called by ISRs, but timeout must be set to K_NO_WAIT.
- Return
A pointer to valid heap memory, or NULL
- Parameters
h
: Heap from which to allocatebytes
: Desired size of block to allocatetimeout
: How long to wait, or K_NO_WAIT
-
void
k_heap_free
(struct k_heap *h, void *mem)¶ Free memory allocated by k_heap_alloc()
Returns the specified memory block, which must have been returned from k_heap_alloc(), to the heap for use by other callers. Passing a NULL block is legal, and has no effect.
- Parameters
h
: Heap to which to return the memorymem
: A valid memory block, or NULL
-
void *
k_aligned_alloc
(size_t align, size_t size)¶ Allocate memory from the heap with a specified alignment.
This routine provides semantics similar to aligned_alloc(); memory is allocated from the heap with a specified alignment. However, one minor difference is that k_aligned_alloc() accepts any non-zero
size
, wherase aligned_alloc() only accepts asize
that is an integral multiple ofalign
.Above, aligned_alloc() refers to: C11 standard (ISO/IEC 9899:2011): 7.22.3.1 The aligned_alloc function (p: 347-348)
- Return
Address of the allocated memory if successful; otherwise NULL.
- Parameters
align
: Alignment of memory requested (in bytes).size
: Amount of memory requested (in bytes).
-
static inline void *
k_malloc
(size_t size)¶ Allocate memory from the heap.
This routine provides traditional malloc() semantics. Memory is allocated from the heap memory pool.
- Return
Address of the allocated memory if successful; otherwise NULL.
- Parameters
size
: Amount of memory requested (in bytes).
-
void
k_free
(void *ptr)¶ Free memory allocated from heap.
This routine provides traditional free() semantics. The memory being returned must have been allocated from the heap memory pool or k_mem_pool_malloc().
If ptr is NULL, no operation is performed.
- Return
N/A
- Parameters
ptr
: Pointer to previously allocated memory.
-
void *
k_calloc
(size_t nmemb, size_t size)¶ Allocate memory from heap, array style.
This routine provides traditional calloc() semantics. Memory is allocated from the heap memory pool and zeroed.
- Return
Address of the allocated memory if successful; otherwise NULL.
- Parameters
nmemb
: Number of elements in the requested arraysize
: Size of each array element (in bytes).
-
struct
k_heap
¶ - #include <kernel.h>
-