memory slab 是一个内核对象,它允许从指定的内存区域动态分配内存块。 memory slab 中的所有内存块都有一个固定大小,可以高效地分配和释放它们,避免出现内存碎片问题。
我正在学习 Zephyr,一个很可能会用到很多物联网设备上的操作系统,如果你也感兴趣,可点此查看帖子zephyr学习笔记汇总。
可以定义任意数量的 memory slab。每个 memory slab 都由其内存地址引用。
memory slab 具有以下关键属性:
memory slab 的缓冲区必须与N字节边界对齐,其中N是大于2的幂(即4,8,16,…)。为确保缓冲区中的所有内存块与此边界相似,块大小必须也是N的倍数。
内存板必须初始化才能使用。这将其所有块都标记为未使用。
需要使用内存块的线程只需向 memory slab 申请分配。当线程完成一个内存块时,它必须将块释放回 memory slab ,以便块可以重用。
如果所有块都在使用中,线程可以选择等待一个可用的块。可能会有任何数量的线程同时在空的 memory slab 上等待; 当内存块变得可用时,它被赋予等待时间最长的最高优先级线程。
与堆不同,如果需要,可以定义多个内存块。可定义一个由较小内存块组成的 memory slab,同时再定义其他较大内存块组成的 memory slab。或者,可以使用内存池对象。
memory slab 的缓冲区是一个固定大小的块的数组,块之间没有浪费的空间。
memory slab 使用链接链表跟踪未分配的块; 每个未使用块的前4个字节提供必要的链接。
memory slab 是使用 struct k_mem_slab 类型的变量定义的。 它必须通过调用 k_mem_slab_init() 来初始化。
以下代码定义并初始化一个 memory slab ,该 slab 有6个长度为400个字节的块,每个块都对齐到一个4字节的边界。
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);
或者,可以在编译时通过调用 K_MEM_SLAB_DEFINE 来定义和初始化 memory slab。
以下代码与上面的代码段具有相同的效果。 观察宏定义了 memory slab 和它的缓冲区。
K_MEM_SLAB_DEFINE(my_slab, 400, 6, 4);
内存块通过调用 k_mem_slab_alloc() 来分配。
以下代码构建在上面的示例上,并等待100毫秒以使内存块变为可用,然后用零填充它。 如果没有获得合适的块,则会打印警告。
char *block_ptr;
if (k_mem_slab_alloc(&my_slab, &block_ptr, 100) == 0)) {
memset(block_ptr, 0, 400);
...
} else {
printf("Memory allocation time-out");
}
通过调用 k_mem_slab_free() 来释放内存块。
以下代码构建在上面的示例上,并分配一个内存块,然后在不再需要时释放它。
char *block_ptr;
k_mem_slab_alloc(&my_slab, &block_ptr, K_FOREVER);
... /* use memory block pointed at by block_ptr */
k_mem_slab_free(&my_slab, &block_ptr);
使用 memory slab 来分配和释放固定大小块中的内存。
从一个线程向另一个线程发送大量数据时使用 memory slab 的块,以避免不必要的数据复制。
无
下列 memory slab API,都在 kernel.h 中提供了:
K_MEM_SLAB_DEFINE
k_mem_slab_init()
k_mem_slab_alloc()
k_mem_slab_free()
k_mem_slab_num_used_get()
k_mem_slab_num_free_get()