154 lines
4.5 KiB
ReStructuredText
154 lines
4.5 KiB
ReStructuredText
.. _memory_slabs_v2:
|
|
|
|
Memory Slabs
|
|
############
|
|
|
|
A :dfn:`memory slab` is a kernel object that allows memory blocks
|
|
to be dynamically allocated from a designated memory region.
|
|
All memory blocks in a memory slab have a single fixed size,
|
|
allowing them to be allocated and released efficiently
|
|
and avoiding memory fragmentation concerns.
|
|
|
|
.. contents::
|
|
:local:
|
|
:depth: 2
|
|
|
|
Concepts
|
|
********
|
|
|
|
Any number of memory slabs can be defined (limited only by available RAM). Each
|
|
memory slab is referenced by its memory address.
|
|
|
|
A memory slab has the following key properties:
|
|
|
|
* The **block size** of each block, measured in bytes.
|
|
It must be at least 4N bytes long, where N is greater than 0.
|
|
|
|
* The **number of blocks** available for allocation.
|
|
It must be greater than zero.
|
|
|
|
* A **buffer** that provides the memory for the memory slab's blocks.
|
|
It must be at least "block size" times "number of blocks" bytes long.
|
|
|
|
The memory slab's buffer must be aligned to an N-byte boundary, where
|
|
N is a power of 2 larger than 2 (i.e. 4, 8, 16, ...). To ensure that
|
|
all memory blocks in the buffer are similarly aligned to this boundary,
|
|
the block size must also be a multiple of N.
|
|
|
|
A memory slab must be initialized before it can be used. This marks all of
|
|
its blocks as unused.
|
|
|
|
A thread that needs to use a memory block simply allocates it from a memory
|
|
slab. When the thread finishes with a memory block,
|
|
it must release the block back to the memory slab so the block can be reused.
|
|
|
|
If all the blocks are currently in use, a thread can optionally wait
|
|
for one to become available.
|
|
Any number of threads may wait on an empty memory slab simultaneously;
|
|
when a memory block becomes available, it is given to the highest-priority
|
|
thread that has waited the longest.
|
|
|
|
Unlike a heap, more than one memory slab can be defined, if needed. This
|
|
allows for a memory slab with smaller blocks and others with larger-sized
|
|
blocks. Alternatively, a memory pool object may be used.
|
|
|
|
Internal Operation
|
|
==================
|
|
|
|
A memory slab's buffer is an array of fixed-size blocks,
|
|
with no wasted space between the blocks.
|
|
|
|
The memory slab keeps track of unallocated blocks using a linked list;
|
|
the first 4 bytes of each unused block provide the necessary linkage.
|
|
|
|
Implementation
|
|
**************
|
|
|
|
Defining a Memory Slab
|
|
======================
|
|
|
|
A memory slab is defined using a variable of type :c:type:`k_mem_slab`.
|
|
It must then be initialized by calling :c:func:`k_mem_slab_init`.
|
|
|
|
The following code defines and initializes a memory slab that has 6 blocks
|
|
that are 400 bytes long, each of which is aligned to a 4-byte boundary.
|
|
|
|
.. code-block:: c
|
|
|
|
struct k_mem_slab my_slab;
|
|
char __aligned(4) my_slab_buffer[6 * 400];
|
|
|
|
k_mem_slab_init(&my_slab, my_slab_buffer, 400, 6);
|
|
|
|
Alternatively, a memory slab can be defined and initialized at compile time
|
|
by calling :c:macro:`K_MEM_SLAB_DEFINE`.
|
|
|
|
The following code has the same effect as the code segment above. Observe
|
|
that the macro defines both the memory slab and its buffer.
|
|
|
|
.. code-block:: c
|
|
|
|
K_MEM_SLAB_DEFINE(my_slab, 400, 6, 4);
|
|
|
|
Similarly, you can define a memory slab in private scope:
|
|
|
|
.. code-block:: c
|
|
|
|
K_MEM_SLAB_DEFINE_STATIC(my_slab, 400, 6, 4);
|
|
|
|
Allocating a Memory Block
|
|
=========================
|
|
|
|
A memory block is allocated by calling :c:func:`k_mem_slab_alloc`.
|
|
|
|
The following code builds on the example above, and waits up to 100 milliseconds
|
|
for a memory block to become available, then fills it with zeroes.
|
|
A warning is printed if a suitable block is not obtained.
|
|
|
|
.. code-block:: c
|
|
|
|
char *block_ptr;
|
|
|
|
if (k_mem_slab_alloc(&my_slab, (void **)&block_ptr, K_MSEC(100)) == 0) {
|
|
memset(block_ptr, 0, 400);
|
|
...
|
|
} else {
|
|
printf("Memory allocation time-out");
|
|
}
|
|
|
|
Releasing a Memory Block
|
|
========================
|
|
|
|
A memory block is released by calling :c:func:`k_mem_slab_free`.
|
|
|
|
The following code builds on the example above, and allocates a memory block,
|
|
then releases it once it is no longer needed.
|
|
|
|
.. code-block:: c
|
|
|
|
char *block_ptr;
|
|
|
|
k_mem_slab_alloc(&my_slab, (void **)&block_ptr, K_FOREVER);
|
|
... /* use memory block pointed at by block_ptr */
|
|
k_mem_slab_free(&my_slab, (void *)block_ptr);
|
|
|
|
Suggested Uses
|
|
**************
|
|
|
|
Use a memory slab to allocate and free memory in fixed-size blocks.
|
|
|
|
Use memory slab blocks when sending large amounts of data from one thread
|
|
to another, to avoid unnecessary copying of the data.
|
|
|
|
Configuration Options
|
|
*********************
|
|
|
|
Related configuration options:
|
|
|
|
* :kconfig:option:`CONFIG_MEM_SLAB_TRACE_MAX_UTILIZATION`
|
|
|
|
API Reference
|
|
*************
|
|
|
|
.. doxygengroup:: mem_slab_apis
|