首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >VPP内存池使用说明

VPP内存池使用说明

原创
作者头像
一觉醒来写程序
发布2025-10-11 09:30:23
发布2025-10-11 09:30:23
1790
举报
文章被收录于专栏:vpp开发与应用vpp开发与应用

本文已同步至:

个人博客:itwakeup.com

微信公众号:vpp与dpdk研习社(vpp_dpdk_lab)

一、引言

在高性能网络数据平面编程中,频繁的内存分配和释放操作往往会成为性能瓶颈。传统的malloc/free不仅性能开销大,还容易造成内存碎片。VPP基于向量(vector)和位图(bitmap)实现了一套高效的内存池(Pool)机制来解决这些问题。

二、核心数据结构

2.1 池的内存布局

VPP的内存池实际上是一个特殊的向量,内存布局如下:

代码语言:plain
复制
+------------------+------------------+------------------+-----+
| pool_header_t    | Element 0        | Element 1        | ... |
+------------------+------------------+------------------+-----+
^                  ^
|                  |
header             pool pointer (用户可见)

用户操作的pool指针指向实际的元素数组,而pool_header_t通过pool_header()函数获取,它复用了向量的header机制。

2.2 pool_header_t 结构体

代码语言:c
复制
typedef struct
{
  /** Bitmap of indices of free objects. */
  uword *free_bitmap;

  /** Vector of free indices.  One element for each set bit in bitmap. */
  u32 *free_indices;

  /* The following fields are set for fixed-size, preallocated pools */
  /** Maximum size of the pool, in elements */
  u32 max_elts;

} pool_header_t;

这个结构体是内存池的元数据头,每个pool都有一个对应的header。关键字段说明:

  • free_bitmap: 空闲对象的位图索引
    • 每一位对应池中的一个对象槽位
    • 位值为1表示该槽位是空闲的,可以分配
    • 位值为0表示该槽位已被占用
    • 用于快速判断某个槽位被分配的情况
  • free_indices: 空闲索引的向量
    • 存储所有空闲对象的索引
    • 只包含空闲的索引,free_indices的长度等于free_bitmap中置位(值为1)的数量
    • 被当做栈使用,可快速获取空闲的槽位
  • max_elts: 最大元素数量
    • 用于固定大小、预分配的内存池
    • 如果为0,表示这是一个可动态扩展的池
    • 如果非0,池容量固定,达到上限后无法扩展
代码语言:plain
复制
池数组:        [obj0]  [obj1]  [obj2]  [obj3]  [obj4]
索引:            0       1       2       3       4
free_bitmap:     0       1       0       1       0     (1=空闲, 0=使用中)
free_indices:   [1, 3]                                 (只存储空闲的索引)

三、扩容机制及可能带来的问题

扩容触发条件

扩容发生在pool_get()时,当同时满足:

  • 没有空闲对象(free_indices 为空)
  • 不是固定大小池(max_elts == 0

扩容策略

VPP采用 1.5倍增长策略,即新容量 = 当前需求 + 当前需求 / 2

扩容过程

步骤:

  1. 调用 realloc() 重新分配更大的内存
  2. 如果原地扩展失败,分配新内存并拷贝数据
  3. 更新池指针(地址可能改变)
  4. 返回新分配的对象

危险操作

扩容后地址可能发生改变,之前保存的指针会失效!例如:

代码语言:c
复制
entry_t *old_ptr = &pool[5];  // 保存指针
...
pool_get(pool, new_entry);    // 触发扩容,pool地址改变,此时old_ptr是野指针!

安全做法:保存索引而不是指针

代码语言:c
复制
u32 index = 5;  // 保存索引
...
pool_get(pool, new_entry); // 触发扩容,
entry_t *ptr = &pool[index];  // 通过索引访问新地址

四、核心接口函数

3.1 内存池初始化

pool_init_fixed - 初始化固定大小池
代码语言:c
复制
#define pool_init_fixed(P, E)
  • 参数
    • P: 池指针
    • E: 最大元素数量
  • 返回值:无(void)
  • 功能:创建一个容量固定的内存池,不能动态扩展,常用语已知对象数量上限,可严格控制内存使用。
pool_alloc - 针对可动态扩容内存池,预分配元素(非必须)
代码语言:c
复制
#define pool_alloc(P, N)
#define pool_alloc_aligned(P, N, A)
#define pool_alloc_aligned_heap(P, N, A, H)
  • 参数
    • P: 池指针(输入/输出,可能会被修改)
    • N: 要预分配的元素数量(uword类型)
    • A: 内存对齐要求(可选)
    • H: 指定堆(可选,0表示默认堆)
  • 返回值:无(void)
  • 功能:预先为池分配N个元素的空间。对于可动态扩容的内存池,也可以不预先分配。
  • 效果:后续N次pool_get不会触发内存重新分配
pool_dup - 复制池
代码语言:c
复制
#define pool_dup(P)
#define pool_dup_aligned(P, A)
  • 参数
    • P: 源池指针
    • A: 内存对齐要求
  • 返回值:新池指针,类型与源池相同
  • 功能:创建池的完整深拷贝,包括:
    • 所有活动对象的内容
    • free_bitmap和free_indices的状态
    • 池的所有元数据

3.2 内存池销毁

pool_free - 释放整个池
代码语言:c
复制
#define pool_free(p)
  • 参数
    • p: 池指针(输入/输出,释放后会被设为NULL)
  • 返回值:无(void)
  • 功能:释放池及其所有资源,包括位图和空闲索引向量。

3.3 对象分配

pool_get - 从池中分配对象
代码语言:c
复制
#define pool_get(P, E)
  • 参数
    • P: 池指针(输入/输出,可能会被修改
    • E: 输出参数,指向分配的对象(对象指针类型)
  • 返回值:无(void),通过参数E返回分配的对象指针
  • 功能:从池中分配一个对象,优先使用空闲对象,如果无空闲对象:
    • 可动态扩展的内存池,将自动扩展
    • 固定大小的内存池,将会立即终止(abort)!
  • 工作流程
    1. 首先检查free_indices是否有空闲对象
    2. 如果有,从free_indices末尾取出一个索引
    3. 在free_bitmap中清除对应的位
    4. 返回该索引对应的对象指针
    5. 对于可动态扩展的池,如果没有空闲对象则扩展池大小

关键实现 (_pool_get函数):

代码语言:c
复制
static_always_inline void
_pool_get (void **pp, void **ep, uword align, int zero, uword elt_sz)
{
  // 优先从空闲列表分配
  if (n_free)
  {
    uword index = ph->free_indices[n_free - 1];
    e = p + index * elt_sz;
    ph->free_bitmap = clib_bitmap_andnoti_notrim (ph->free_bitmap, index);
    vec_set_len (ph->free_indices, n_free - 1);
    clib_mem_unpoison (e, elt_sz);
    goto done;
  }
  
  // 如果是固定池且没有空闲对象,报错
  if (ph->max_elts)
  {
    clib_warning ("can't expand fixed-size pool");
    os_out_of_memory ();
  }
  
  // 否则扩展池
  p = _vec_realloc_internal (p, len + 1, &va);
  e = p + len * elt_sz;
}
pool_get_zero - 分配并清零
代码语言:c
复制
#define pool_get_zero(P, E)
  • 参数
    • P: 池指针(输入/输出,可能会被修改)
    • E: 输出参数,指向分配的对象
  • 返回值:无(void),通过参数E返回分配的对象指针
  • 功能:能与pool_get相同,但会将分配的对象内存清零
pool_get_aligned - 按指定对齐分配
代码语言:c
复制
#define pool_get_aligned(P, E, A)
  • 参数
    • P: 池指针(输入/输出,可能会被修改)
    • E: 输出参数,指向分配的对象
    • A: 内存对齐要求(字节数,通常是2的幂次)
  • 返回值:无(void),通过参数E返回分配的对象指针
  • 功能:分配对象时保证指定的内存对齐要求

3.3 对象释放

pool_put - 释放对象
代码语言:c
复制
#define pool_put(P, E)
  • 参数
    • P: 池指针(输入)
    • E: 要释放的对象指针(必须是通过pool_get从该池分配的对象)
  • 返回值:无(void)
  • 功能:将对象标记为空闲,可被后续pool_get重用
  • 工作流程
    1. 计算对象的索引:index = E - P
    2. 在free_bitmap中设置对应的位
    3. 将索引添加到free_indices向量
    4. 对释放的内存区域进行poison标记(调试用)

关键实现 (_pool_put_index函数):

代码语言:c
复制
static_always_inline void
_pool_put_index (void *p, uword index, uword elt_sz)
{
  pool_header_t *ph = pool_header (p);
  
  ASSERT (index < ph->max_elts ? ph->max_elts : vec_len (p));
  ASSERT (!pool_is_free_index (p, index));
  
  // 在位图中标记为空闲
  ph->free_bitmap = clib_bitmap_ori_notrim (ph->free_bitmap, index);
  
  // 添加到空闲索引列表
  if (ph->max_elts)
  {
    u32 len = _vec_len (ph->free_indices);
    vec_set_len (ph->free_indices, len + 1);
    ph->free_indices[len] = index;
  }
  else
    vec_add1 (ph->free_indices, index);
  
  clib_mem_poison (p + index * elt_sz, elt_sz);
}
pool_put_index - 按索引释放
代码语言:c
复制
#define pool_put_index(P, I)
  • 参数
    • P: 池指针(输入,不会被修改)
    • I: 要释放的对象索引(u32或uword类型)
  • 返回值:无(void)
  • 功能:直接通过索引释放对象,不需要对象指针
  • 应用场景:当你只有索引而没有对象指针时使用
  • 等价于pool_put(P, &P[I])

3.4 池的查询和管理

pool_elts - 获取活动元素数量
代码语言:c
复制
always_inline uword pool_elts (void *v)
  • 参数
    • v: 池指针(void *类型,可以传入任何类型的池)
  • 返回值:uword类型,表示当前使用中的元素数量
  • 功能:返回池中当前被使用的元素数量(总容量 - 空闲数)
  • 计算公式pool_len(p) - vec_len(free_indices)
pool_len - 获取池的总容量
代码语言:c
复制
#define pool_len(p)
  • 参数
    • p: 池指针
  • 返回值:uword类型,表示池的总容量
  • 功能:返回池的总容量(包括已使用和空闲的所有槽位)
  • 注意:这是池向量的长度,不是使用中的对象数量
pool_free_elts - 获取空闲元素数量
代码语言:c
复制
#define pool_free_elts(P)
  • 参数
    • P: 池指针
  • 返回值:uword类型,表示可用的空闲元素数量
  • 功能:返回池中可用的空闲元素数量,该值为free_indices(已释放的对象) + 预留的未使用空间(pool_max_len - pool_len)。
pool_is_free / pool_is_free_index - 检查对象是否空闲
代码语言:c
复制
#define pool_is_free(P, E)

int pool_is_free_index (void *p, uword index)
  • 参数
    • P: 池指针
    • E: 对象指针(pool_is_free)或 索引(pool_is_free_index)
    • index: 要检查的索引(uword类型)
  • 返回值:int类型,1表示空闲,0表示使用中
  • 功能:通过位图检查指定索引的对象是否空闲
  • 应用场景:在使用对象前验证其是否有效,防止use-after-free错误
pool_max_len - 获取池的最大容量
代码语言:c
复制
#define pool_max_len(P) vec_max_len(P)
  • 参数
    • P: 池指针
  • 返回值:uword类型,表示池当前分配的最大容量
  • 功能:返回池在不重新分配的情况下可以容纳的最大元素数
  • 区别:pool_len是当前长度,pool_max_len是已分配的容量
pool_bytes - 计算池的内存使用
代码语言:c
复制
#define pool_bytes(P)
  • 参数
    • P: 池指针
  • 返回值:uword类型,表示池占用的总字节数
  • 功能:计算池占用的总内存,包括:
    • 对象数组的内存
    • free_bitmap的内存
    • free_indices的内存
    • pool_header的内存
  • 应用场景:内存使用统计和监控
pool_validate - 验证池的完整性
代码语言:c
复制
always_inline void pool_validate (void *v)
  • 参数
    • v: 池指针
  • 返回值:无(void)
  • 功能:验证池的内部数据结构一致性,包括:
    • free_bitmap中置位的数量 = free_indices的长度
    • free_indices中的每个索引在free_bitmap中都是1
  • 用途:调试工具,检测池是否被破坏
  • 注意:包含断言,如果验证失败会终止程序

3.5 池的遍历

pool_foreach - 遍历所有活动对象
代码语言:c
复制
#define pool_foreach(VAR, POOL)
  • 参数
    • VAR: 迭代器变量,类型与池元素类型相同的指针
    • POOL: 要遍历的池
  • 返回值:无(这是一个循环结构宏)
  • 功能:遍历池中所有活动(非空闲)的对象

使用示例

代码语言:c
复制
proc_t *procs;   // 进程池
proc_t *proc;

pool_foreach (proc, procs)
{
  if (proc->state != PROC_STATE_RUNNING)
    continue;
    
  // 处理运行中的进程
  process_running_proc(proc);
}

注意事项

  • 不要在遍历过程中分配或释放池元素
  • 如需删除,应该先收集索引到向量,遍历结束后再删除
  • 或者使用pool_flush
pool_foreach_index - 按索引遍历
代码语言:c
复制
#define pool_foreach_index(i, v)
  • 参数
    • i: 迭代器变量,uword类型,存储当前对象的索引
    • v: 要遍历的池
  • 返回值:无(这是一个循环结构宏)
  • 功能:遍历所有活动对象的索引,不返回对象指针
pool_elt_at_index - 通过索引访问元素
代码语言:c
复制
#define pool_elt_at_index(p, i)
  • 参数
    • p: 池指针
    • i: 元素索引(uword类型)
  • 返回值:指向索引i处对象的指针
  • 功能:返回指定索引处的对象指针,并断言该对象不是空闲的
  • 注意:包含断言检查,确保索引有效且对象在使用中
  • 等价于&p[i] 但带有安全检查
pool_foreach_pointer - 遍历指针池
代码语言:c
复制
#define pool_foreach_pointer(e, p)
  • 参数
    • e: 迭代器变量,存储当前指针指向的值
    • p: 指针类型的池(池元素是指针)
  • 返回值:无(这是一个循环结构宏)
  • 功能:专门用于池元素是指针类型的场景,遍历时自动解引用。
  • 应用场景:当池中存储的是指针(如 session_t **pool)时使用。

指针池使用该接口和通用接口的区别:

1)使用通用接口遍历,需要手动解引用:

代码语言:c
复制
object_t **object_pool = 0;  // 指针池

object_t **obj_ptr;  // 迭代器是指针的指针
pool_foreach(obj_ptr, object_pool) {
  object_t *obj = *obj_ptr;  // 需要手动解引用
  process(obj);
}

2)使用该接口,自动解引用:

代码语言:c
复制
object_t **object_pool = 0;  // 指针池

object_t *obj;  // 迭代器直接是对象指针
pool_foreach_pointer(obj, object_pool) {
  // 自动解引用,直接使用!
  process(obj);
}
pool_flush - 安全地清空池
代码语言:c
复制
#define pool_flush(VAR, POOL, BODY)
  • 参数
    • VAR: 迭代器变量,类型与池元素类型相同的指针
    • POOL: 要清空的池
    • BODY: 对每个元素执行的操作(代码块)
  • 返回值:无(void)
  • 功能:遍历所有元素,对每个元素执行BODY操作,然后释放该元素
  • 特点:这是唯一安全的在遍历中删除元素的方法
  • 应用场景:清理资源并释放所有对象

使用示例

代码语言:c
复制
buffer_entry_t *entry;
pool_flush(entry, buffer_pool, {
  // 在删除前释放资源
  if (entry->data)
    free_buffer_data(entry->data);
});
// 执行完后,buffer_pool为空但仍可用

五、使用示例

以下示例均以独立文件编译,假设你已编译好vpp,gcc参数根据你的环境修改。

代码语言:bash
复制
gcc -o test_pool_simple test_pool_simple.c  \
   -I./build-root/install-vpp_debug-native/vpp/include   \
   -L./build-root/install-vpp_debug-native/vpp/lib64   \
   -Wl,-rpath,./build-root/install-vpp_debug-native/vpp/lib64   \
   -lvppinfra

4.1 可动态扩容的内存池示例

该示例为可动态扩容的内存池:

  • 未执行预分配元素,将会在第一次pool_get的时候扩容。
  • 演示了元素的添加、删除、遍历。
  • 内存池统计,总个数、活跃个数、空闲个数。
  • 内存池的释放。
代码语言:c
复制
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vppinfra/pool.h>
#include <vppinfra/mem.h>

typedef struct test_entry
{
  u32 id;
  u8 data[32];
} test_entry_t;

int
main (int argc, char **argv)
{
  clib_mem_init (0, 64 << 20); // 64MB heap

  test_entry_t *pool = 0;
  test_entry_t *entry = 0;

  printf ("=== VPP Pool Test Program ===\n");
  printf ("Initial pool pointer: %p\n\n", pool);

  // 1. Add elements
  printf ("--- Adding Elements ---\n");
  for (int i = 0; i < 4; i++)
    {
      pool_get (pool, entry);
      entry->id = i + 100;
      memset (entry->data, i + 'A', sizeof (entry->data));
      printf ("Added element: id=%d, index=%ld, pool_addr=%p\n", entry->id,
	      entry - pool, pool);
    }

  // 2. Display pool status
  printf ("\n--- Pool Status ---\n");
  printf ("Total elements (pool_len): %u\n", pool_len (pool));
  printf ("Active elements (pool_elts): %lu\n", pool_elts (pool));
  printf ("Free elements (pool_free_elts): %lu\n", pool_free_elts (pool));

  // 3. Iterate all elements
  printf ("\n--- Iterate All Elements (pool_foreach) ---\n");
  pool_foreach (entry, pool)
    {
      printf ("Element[%ld]: id=%d, data[0]=%c\n", entry - pool, entry->id,
	      entry->data[0]);
    }

  // 4. Delete some elements
  printf ("\n--- Deleting Elements ---\n");
  entry = pool_elt_at_index (pool, 1);
  printf ("Delete element: index=1, id=%d\n", entry->id);
  pool_put (pool, entry);

  entry = pool_elt_at_index (pool, 3);
  printf ("Delete element: index=3, id=%d\n", entry->id);
  pool_put (pool, entry);

  // 5. Display status again
  printf ("\n--- Pool Status After Deletion ---\n");
  printf ("Total elements: %u\n", pool_len (pool));
  printf ("Active elements: %lu\n", pool_elts (pool));
  printf ("Free elements: %lu\n", pool_free_elts (pool));

  // 6. Iterate by index
  printf ("\n--- Iterate by Index (pool_foreach_index) ---\n");
  u32 index;
  pool_foreach_index (index, pool)
    {
      entry = pool_elt_at_index (pool, index);
      printf ("Element[%d]: id=%d, data[0]=%c\n", index, entry->id,
	      entry->data[0]);
    }

  // 7. Add new elements (reuse freed slots)
  printf ("\n--- Adding New Elements (Reuse Free Slots) ---\n");
  pool_get (pool, entry);
  entry->id = 200;
  memset (entry->data, 'X', sizeof (entry->data));
  printf ("Added new element: id=%d, index=%ld (Notice: index reused!)\n",
	  entry->id, entry - pool);

  pool_get (pool, entry);
  entry->id = 201;
  memset (entry->data, 'Y', sizeof (entry->data));
  printf ("Added new element: id=%d, index=%ld\n", entry->id, entry - pool);

  // 8. Final iteration
  printf ("\n--- Final Iteration ---\n");
  pool_foreach (entry, pool)
    {
      printf ("Element[%ld]: id=%d, data[0]=%c\n", entry - pool, entry->id,
	      entry->data[0]);
    }

  // 9. Display final status
  printf ("\n--- Final Pool Status ---\n");
  printf ("Total elements: %u\n", pool_len (pool));
  printf ("Active elements: %lu\n", pool_elts (pool));
  printf ("Free elements: %lu\n", pool_free_elts (pool));

  // 10. Cleanup pool
  printf ("\n--- Freeing Pool ---\n");
  pool_free (pool);
  printf ("Pool freed, pointer=%p\n", pool);

  printf ("\n=== Test Completed ===\n");
  return 0;
}

运行结果如下,需要注意的是,Free elements包含了已释放的和预留未被使用的元素之和:

代码语言:bash
复制
Initial pool pointer: (nil)

--- Adding 4 Elements ---
Added element: id=100, index=0, pool_addr=0x7faf8f1e6420
Added element: id=101, index=1, pool_addr=0x7faf8f1e6420
Added element: id=102, index=2, pool_addr=0x7faf8f1e6420
Added element: id=103, index=3, pool_addr=0x7faf8f1e6420

--- Pool Status ---
Total elements (pool_len): 4
Active elements (pool_elts): 4
Free elements (pool_free_elts): 2

--- Iterate All Elements (pool_foreach) ---
Element[0]: id=100, data[0]=A
Element[1]: id=101, data[0]=B
Element[2]: id=102, data[0]=C
Element[3]: id=103, data[0]=D

--- Deleting Elements ---
Delete element: index=1, id=101
Delete element: index=3, id=103

--- Pool Status After Deletion ---
Total elements: 4
Active elements: 2
Free elements: 4

--- Iterate by Index (pool_foreach_index) ---
Element[0]: id=100, data[0]=A
Element[2]: id=102, data[0]=C

--- Adding New Elements (Reuse Free Slots) ---
Added new element: id=200, index=3 (Notice: index reused!)
Added new element: id=201, index=1

--- Final Iteration ---
Element[0]: id=100, data[0]=A
Element[1]: id=201, data[0]=Y
Element[2]: id=102, data[0]=C
Element[3]: id=200, data[0]=X

--- Final Pool Status ---
Total elements: 4
Active elements: 4
Free elements: 2

--- Freeing Pool ---
Pool freed, pointer=(nil)

4.2 固定大小的内存池

该示例为可固定大小的内存池:

  • 初始化指定内存池大小。
  • 当内存池已空,再次get将会失败。
  • 演示了如何安全地在遍历时删除元素。
代码语言:c
复制
Initial pool pointer: 0x7f81aeaf1420

--- Adding 4 Elements ---
Added element: id=100, index=0, pool_addr=0x7f81aeaf1420
Added element: id=101, index=1, pool_addr=0x7f81aeaf1420
Added element: id=102, index=2, pool_addr=0x7f81aeaf1420
pool is empty, add element failed

--- Pool Status ---
Total elements (pool_len): 3
Active elements (pool_elts): 3
Free elements (pool_free_elts): 0

--- Iterate All Elements (pool_foreach) ---
Element[0]: id=100, data[0]=A
Element[1]: id=101, data[0]=B
Element[2]: id=102, data[0]=C

--- Deleting Elements ---
Delete element: index=1, id=101

--- Pool Status After Deletion ---
Total elements: 3
Active elements: 2
Free elements: 1

--- flush pool ---
Element[4198528]: id=100, data[0]=A
free something
Element[4198528]: id=102, data[0]=C
free something

--- Freeing Pool ---
Pool freed, pointer=(nil)

运行结果:

代码语言:c
复制
Initial pool pointer: 0x7f02953cc420

--- Adding 4 Elements ---
Added element: id=100, index=0, pool_addr=0x7f02953cc420
Added element: id=101, index=1, pool_addr=0x7f02953cc420
Added element: id=102, index=2, pool_addr=0x7f02953cc420
pool is empty, add element failed

--- Pool Status ---
Total elements (pool_len): 3
Active elements (pool_elts): 3
Free elements (pool_free_elts): 0

--- Iterate All Elements (pool_foreach) ---
Element[0]: id=100, data[0]=A
Element[1]: id=101, data[0]=B
Element[2]: id=102, data[0]=C

--- Deleting Elements ---
Delete element: index=1, id=101

--- Pool Status After Deletion ---
Total elements: 3
Active elements: 2
Free elements: 1

--- flush pool ---
Element[0]: id=100, data[0]=A
free something
Element[2]: id=102, data[0]=C
free something

--- Freeing Pool ---
Pool freed, pointer=(nil)

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、引言
  • 二、核心数据结构
    • 2.1 池的内存布局
    • 2.2 pool_header_t 结构体
  • 三、扩容机制及可能带来的问题
    • 扩容触发条件
    • 扩容策略
    • 扩容过程
    • 危险操作
  • 四、核心接口函数
    • 3.1 内存池初始化
      • pool_init_fixed - 初始化固定大小池
      • pool_alloc - 针对可动态扩容内存池,预分配元素(非必须)
      • pool_dup - 复制池
    • 3.2 内存池销毁
      • pool_free - 释放整个池
    • 3.3 对象分配
      • pool_get - 从池中分配对象
      • pool_get_zero - 分配并清零
      • pool_get_aligned - 按指定对齐分配
    • 3.3 对象释放
      • pool_put - 释放对象
      • pool_put_index - 按索引释放
    • 3.4 池的查询和管理
      • pool_elts - 获取活动元素数量
      • pool_len - 获取池的总容量
      • pool_free_elts - 获取空闲元素数量
      • pool_is_free / pool_is_free_index - 检查对象是否空闲
      • pool_max_len - 获取池的最大容量
      • pool_bytes - 计算池的内存使用
      • pool_validate - 验证池的完整性
    • 3.5 池的遍历
      • pool_foreach - 遍历所有活动对象
      • pool_foreach_index - 按索引遍历
      • pool_elt_at_index - 通过索引访问元素
      • pool_foreach_pointer - 遍历指针池
      • pool_flush - 安全地清空池
  • 五、使用示例
    • 4.1 可动态扩容的内存池示例
    • 4.2 固定大小的内存池
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档