分层模型
内存池由浅入深分为三层:
| 层 | 类型 | 适用场景 |
|---|
| 单页 | xpoolpage | 精确控制一个 1 到 256 槽固定对象页,或搭建更高层分配器 |
| 固定池 | xpool | 同一种结构或节点的长期高频分配,按约 64 KiB 目标自适应页容量并自动跨页增长 |
| 变长池 | xmempool | 同一生命周期域内的多尺寸内存,小块池化,大块独立登记 |
旧版 MemUnit 的 256 槽默认布局、空闲槽复用、满页边界和显式标记回收被保留;重复实现多页固定块管理的 BSMM 与 FSMemPool 合并为 xpool。多页固定池不再把每种对象都机械放大为 256 个槽:小对象仍保持 256 槽吞吐,大对象按目标页字节数降低槽数。xmempool 继续采用 16 字节尺寸类和默认 1024 字节分界,但删除了未参与当前分配路径的二叉树、LUT 和对象前 4 字节头。
三个层次都可独立裁剪。XRT_FEATURE_POOL 依赖 XRT_FEATURE_POOL_PAGE,XRT_FEATURE_MEMORY_POOL 依赖前两层。
旧版资产复用
这三层实现逐项审计了旧版 memunit.h、bsmm.h、mempool_fs.h、mempool.h 及其测试、范例和中英文文档。
保留并加强的资产:
MemUnit 的 256 槽默认容量、释放槽复用、满页失败和“释放标记/释放未标记”两种回收语义。FSMemPool 的跨页增长、满页与可用页迁移、空页缓存策略。MemPool 的小块分级、可配置分界和大块回退路径。- 旧测试中的尺寸边界、256 槽边界、跨页增长、复用与 GC 场景,已改为无需人工查看输出的自动断言。
新增的自适应页容量解决了旧实现的大对象放大问题:显式单页仍可选择旧版 256 槽布局,通用多页池则不会为一个 8 KiB 对象立即申请约 2 MiB,也不会为一个 1 MiB 对象立即申请约 256 MiB。上层 AVLTree 等稳定地址容器直接复用这一能力,无需重复实现大对象旁路。
明确淘汰的实现:
- 用户内存前方的 4 字节管理头。新实现用外置位图、页地址索引和大块哈希登记,避免读取未知指针前方内存,并完整支持显式对齐。
BSMM 和 FSMemPool 两套重叠的多页管理器。其有效能力统一进入 xpool,不保留重复 API 和实现。- 旧变长池未参与最终热路径的树字段与重复 LUT 状态。新尺寸类可直接通过除法定位。
- 打印内部字段、依赖人工判断结果的旧测试形式。有效场景保留,测试方式升级为自动失败。
范例与回归
完整范例位于:
examples/memory/pool_page/main.cexamples/memory/pool/main.cexamples/memory/memory_pool/main.c
三个裁剪层可分别执行:
构建脚本同时运行普通实现、范例和对应单头文件测试。
XRT_POOL_PAGE_CAPACITY常量
单页支持的最大槽数,也是快捷单页入口的默认槽数,值为 256。
XRT_POOL_PAGE_BYTES_DEFAULT常量
多页固定池的默认目标页字节数,值为 65536。自动布局使用 clamp(65536 / stride, 1, 256) 选择每页槽数,其中 stride 是对齐后的实际槽步长。 因此小对象保持 256 槽,大对象不会仅因进入固定池就预留 256 倍对象大小的首批内存。 当单个槽已经超过 64 KiB 时,一页只包含一个槽。
XRT_POOL_ALIGNMENT_DEFAULT常量
默认对象对齐,值为 16。
XRT_MEMPOOL_CLASS_STEP常量
变长池的小块尺寸类步长,值为 16。
XRT_MEMPOOL_CUTOFF_DEFAULT常量
变长池默认小块分界,值为 1024。
xpoolerror类型
内存池错误代码在 xrt.pool 域内稳定。
| 值 | 语义 |
|---|
XPOOL_ERROR_INVALID_POINTER | 无效POINTER |
XPOOL_ERROR_NOT_ALLOCATED | 失败 |
XPOOL_ERROR_PAGE_FULL | PAGE已满 |
XPOOL_ERROR_INVALID_ALIGNMENT | 无效ALIGNMENT |
XPOOL_ERROR_INVALID_SIZE | 无效尺寸 |
XPOOL_ERROR_INDEX_OUT_OF_RANGE | 索引OUTOF范围越界 |
XPOOL_ERROR_VISIT_ACTIVE | 失败 |
XPOOL_ERROR_INVALID_CAPACITY | 容量参数非法 |
typedef enum xpoolerror { XPOOL_ERROR_INVALID_POINTER = 1, XPOOL_ERROR_NOT_ALLOCATED, XPOOL_ERROR_PAGE_FULL, XPOOL_ERROR_INVALID_ALIGNMENT, XPOOL_ERROR_INVALID_SIZE, XPOOL_ERROR_INDEX_OUT_OF_RANGE, XPOOL_ERROR_VISIT_ACTIVE, XPOOL_ERROR_INVALID_CAPACITY } xpoolerror;
xmempoolbucket类型
变长池的 16 字节尺寸类内部桶结构(不透明,仅实现内部使用)。 不透明句柄或别名;生命周期与所有权见各使用方 API 节。
typedef struct xmempoolbucket xmempoolbucket;
xmempoollarge类型
超过池化上限的独立大块登记结构(不透明,仅实现内部使用)。 不透明句柄或别名;生命周期与所有权见各使用方 API 节。
typedef struct xmempoollarge xmempoollarge;
单页池
xpoolpage类型
Allocation 和 Memory 分别是底层分配地址与对齐后的槽区;ItemSize、Stride、Alignment、MemorySize 和 Capacity 描述布局。Used 与 Marked 是外置位图,因而不占用户对象空间。FreeList、LiveCount、NextIndex 和 FreeCount 管理分配状态。四个链指针、Parent 和 Flags 供上层固定池维护页关系,不得由调用方修改。
xpoolpageinfo类型
ItemSize 是用户对象大小,Stride 是实际槽步长,Alignment 是对齐;LiveCount、FreeCount 和 Capacity 分别表示活动槽、可直接复用槽和总槽数。
xrtPoolPageInit函数
使用默认 16 字节对齐初始化一个空的 256 槽页。
bool xrtPoolPageInit(xpoolpage* pPage, size_t iItemSize)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPage | 输出 | 非空 | 接收页 |
iItemSize | 输入 | > 0 | 每槽字节数 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 已初始化 | — |
false | 布局参数非法 | 见错误 |
错误XERR_ARGUMENT — 指针为空或参数非法XERR_RANGE — 项大小或容量为零、溢出XERR_VALUE — 对齐不是二次幂XERR_MEMORY — 槽内存分配失败
范例已编译验证
page · 默认初始化
if ( !xrtPoolPageInit(&DefaultPage, sizeof(uint64)) ) {
xrtPoolPageInitAligned函数
使用指定的二次幂对齐初始化一个空的 256 槽页。
bool xrtPoolPageInitAligned(xpoolpage* pPage, size_t iItemSize, size_t iAlignment)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPage | 输出 | 非空 | 接收页 |
iItemSize | 输入 | > 0 | 每槽字节数 |
iAlignment | 输入 | 二次幂 | 槽对齐 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 已初始化 | — |
false | 布局参数非法 | 见错误 |
错误XERR_ARGUMENT — 指针为空或参数非法XERR_RANGE — 项大小或容量为零、溢出XERR_VALUE — 对齐不是二次幂XERR_MEMORY — 槽内存分配失败
范例已编译验证
page · 对齐初始化
if ( !xrtPoolPageInitAligned(&tPage, sizeof(int), 32) ) {
xrtPoolPageInitLayout函数
使用显式对齐和槽数初始化一个空页。
bool xrtPoolPageInitLayout(xpoolpage* pPage, size_t iItemSize, size_t iAlignment, size_t iCapacity)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPage | 输出 | 非空 | 接收页 |
iItemSize | 输入 | > 0 | 每槽字节数 |
iAlignment | 输入 | 二次幂 | 槽对齐 |
iCapacity | 输入 | > 0 | 槽数 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 已初始化 | — |
false | 布局参数非法 | 见错误 |
错误XERR_ARGUMENT — 指针为空或参数非法XERR_RANGE — 项大小或容量为零、溢出XERR_VALUE — 对齐不是二次幂XERR_MEMORY — 槽内存分配失败
范例已编译验证
page · 完整布局初始化
if ( !xrtPoolPageInitLayout(&LayoutPage, sizeof(uint64),
32u, 8u) ||
(LayoutPage.Capacity != 8u) ) {
xrtPoolPageCreate函数
创建一个使用默认 16 字节对齐的 256 槽页。
xpoolpage* xrtPoolPageCreate(size_t iItemSize)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
iItemSize | 输入 | > 0 | 每槽字节数 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
| 非空 | 页(含槽内存) | — |
NULL | 创建失败 | 见错误 |
错误XERR_ARGUMENT — 指针为空或参数非法XERR_RANGE — 项大小或容量为零、溢出XERR_VALUE — 对齐不是二次幂XERR_MEMORY — 槽内存分配失败
范例已编译验证
page · 创建页
pCreated = xrtPoolPageCreate(sizeof(uint64));
xrtPoolPageCreateAligned函数
创建一个使用指定对齐的 256 槽页。
xpoolpage* xrtPoolPageCreateAligned(size_t iItemSize, size_t iAlignment)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
iItemSize | 输入 | > 0 | 每槽字节数 |
iAlignment | 输入 | 二次幂 | 槽对齐 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
| 非空 | 页(含槽内存) | — |
NULL | 创建失败 | 见错误 |
错误XERR_ARGUMENT — 指针为空或参数非法XERR_RANGE — 项大小或容量为零、溢出XERR_VALUE — 对齐不是二次幂XERR_MEMORY — 槽内存分配失败
范例已编译验证
page · 创建页(对齐)
pAligned = xrtPoolPageCreateAligned(sizeof(uint64), 32u);
xrtPoolPageCreateLayout函数
创建一个使用显式对齐和槽数的页。
xpoolpage* xrtPoolPageCreateLayout(size_t iItemSize, size_t iAlignment, size_t iCapacity)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
iItemSize | 输入 | > 0 | 每槽字节数 |
iAlignment | 输入 | 二次幂 | 槽对齐 |
iCapacity | 输入 | > 0 | 槽数 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
| 非空 | 页(含槽内存) | — |
NULL | 创建失败 | 见错误 |
错误XERR_ARGUMENT — 指针为空或参数非法XERR_RANGE — 项大小或容量为零、溢出XERR_VALUE — 对齐不是二次幂XERR_MEMORY — 槽内存分配失败
范例已编译验证
page · 创建页(完整布局)
pCompact = xrtPoolPageCreateLayout(8192, 64, 4);
xrtPoolPageUnit函数
释放页持有的槽内存,但不释放页结构。
void xrtPoolPageUnit(xpoolpage* pPage)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPage | 输入 | 允许空 | 空 = 空操作 |
范例已编译验证
page · 释放槽内存
xrtPoolPageUnit(&tPage);
xrtPoolPageDestroy函数
释放页持有的全部资源和页结构。
void xrtPoolPageDestroy(xpoolpage* pPage)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPage | 输入 | 允许空 | 空 = 空操作 |
范例已编译验证
page · 销毁页
xrtPoolPageDestroy(pCompact);
xrtPoolPageAlloc函数
分配一个未初始化槽,页满时返回空指针并设置 XERR_AGAIN。
ptr xrtPoolPageAlloc(xpoolpage* pPage)
返回值| 返回 | 含义 | 失败时状态 |
|---|
| 非空 | 槽内存,至少按 16 字节对齐 | — |
NULL | 失败 | 见错误 |
错误XERR_ARGUMENT — 指针为空或参数非法XERR_AGAIN — 页已满,无空闲槽
范例已编译验证
page · 分配槽
pDrop = (int*)xrtPoolPageAlloc(&tPage);
xrtPoolPageCalloc函数
分配并清零一个槽,页满时返回空指针并设置 XERR_AGAIN。
ptr xrtPoolPageCalloc(xpoolpage* pPage)
返回值| 返回 | 含义 | 失败时状态 |
|---|
| 非空 | 槽内存,至少按 16 字节对齐 | — |
NULL | 失败 | 见错误 |
错误XERR_ARGUMENT — 指针为空或参数非法XERR_AGAIN — 页已满,无空闲槽
范例已编译验证
page · 清零分配槽
pKeep = (int*)xrtPoolPageCalloc(&tPage);
xrtPoolPageFree函数
安全释放一个活动槽,非法、跨页或重复释放均返回 false。
bool xrtPoolPageFree(xpoolpage* pPage, ptr pMemory)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPage | 输入 | 非空 | 目标页 |
pMemory | 输入 | 本页活动槽 | 要释放的槽 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 已释放 | — |
false | 非法、跨页或重复释放 | XERR_STATE |
错误XERR_ARGUMENT — 指针为空或参数非法XERR_STATE — 重复释放、指针不属于本对象或内部状态非法
范例已编译验证
page · 释放槽
if ( (pValue == NULL) || !xrtPoolPageFree(&tPage, pValue) ) {
xrtPoolPageFreeAt函数
按槽索引释放活动对象。
bool xrtPoolPageFreeAt(xpoolpage* pPage, size_t iIndex)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPage | 输入 | 非空 | 目标页 |
iIndex | 输入 | < 槽数 | 槽索引 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 已释放 | — |
false | 空闲或越界 | 不设错 |
错误- 空闲槽或索引越界返回
false 且不设置错误;空句柄 XERR_ARGUMENT
范例已编译验证
page · 按索引释放
!xrtPoolPageFreeAt(&tPage, iIndex)
xrtPoolPageGet函数
返回指定索引处的活动对象,空闲或越界时返回空指针。
ptr xrtPoolPageGet(const xpoolpage* pPage, size_t iIndex)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPage | 输入 | 非空 | 目标页 |
iIndex | 输入 | < 槽数 | 槽索引 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
| 非空 | 活动对象 | — |
NULL | 空闲或越界 | 不设错 |
错误- 空闲槽或索引越界返回
NULL 且不设置错误;空句柄 XERR_ARGUMENT
范例已编译验证
page · 按索引取对象
(xrtPoolPageGet(&tPage, iIndex) != pKeep)
xrtPoolPageIndex函数
获取活动对象的槽索引。
bool xrtPoolPageIndex(const xpoolpage* pPage, const void* pMemory, size_t* pIndex)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPage | 输入 | 非空 | 目标页 |
pMemory | 输入 | 本页活动槽 | 目标对象 |
pIndex | 输出 | 非空 | 接收槽索引 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 已写出索引 | — |
false | 非本页活动对象 | XERR_STATE |
错误XERR_ARGUMENT — 指针为空或参数非法XERR_STATE — 重复释放、指针不属于本对象或内部状态非法
范例已编译验证
page · 对象索引
!xrtPoolPageIndex(&tPage, pKeep, &iIndex) ||
xrtPoolPageOwns函数
判断指针当前是否属于该页的活动槽。
bool xrtPoolPageOwns(const xpoolpage* pPage, const void* pMemory)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPage | 输入 | 非空 | 目标页 |
pMemory | 输入 | 任意 | 待判断指针 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 是本页活动槽 | — |
false | 不是本页活动槽 | 不设错误 |
范例已编译验证
page · 归属判断
!xrtPoolPageOwns(&tPage, pKeep) ||
xrtPoolPageMark函数
将一个活动槽标记为本轮可达对象。
bool xrtPoolPageMark(xpoolpage* pPage, ptr pMemory)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPage | 输入/输出 | 非空 | 目标页 |
pMemory | 输入 | 本页活动槽 | 目标对象 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 已标记 | — |
false | 非本页/池活动对象 | XERR_STATE |
错误XERR_ARGUMENT — 指针为空或参数非法XERR_STATE — 重复释放、指针不属于本对象或内部状态非法
范例已编译验证
page · 标记
if ( !xrtPoolPageMark(&tPage, pKeep) || (xrtPoolPageSweep(&tPage) != 1) ) {
xrtPoolPageSweep函数
释放未标记槽,并清除幸存槽的标记。
size_t xrtPoolPageSweep(xpoolpage* pPage)
错误XERR_ARGUMENT — 指针为空或参数非法
范例已编译验证
page · 清扫
if ( !xrtPoolPageMark(&tPage, pKeep) || (xrtPoolPageSweep(&tPage) != 1) ) {
xrtPoolPageFreeMarked函数
释放已标记槽,适合显式批量选择释放。
size_t xrtPoolPageFreeMarked(xpoolpage* pPage)
错误XERR_ARGUMENT — 指针为空或参数非法
范例已编译验证
page · 释放已标记
if ( !xrtPoolPageMark(&tPage, pKeep) || (xrtPoolPageFreeMarked(&tPage) != 1) ) {
xrtPoolPageGetInfo函数
获取单页当前状态。
void xrtPoolPageGetInfo(const xpoolpage* pPage, xpoolpageinfo* pInfo)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPage | 输入 | 非空 | 目标页 |
pInfo | 输出 | 非空 | 接收状态快照 |
错误XERR_ARGUMENT — 指针为空或参数非法
范例已编译验证
page · 状态查询
xrtPoolPageGetInfo(&tPage, &tInfo);
固定对象池
xpool类型
Pages 是全部页链,Available 是可分配页链,Index 是按槽区地址排序的安全查找索引。ItemSize、Alignment、PageCapacity、PageCount、EmptyPages、LiveCount、PeakCount、AllocCount、FreeCount 和 RetainEmpty 提供布局、统计与保留策略。IndexCapacity 和 Flags 是内部状态。
xpoolinfo类型
包含对象大小、步长、对齐、每页槽数、页数、空页数、实时/峰值对象数、总容量和累计分配/释放次数。理论容量无法用 size_t 表示时,Capacity 饱和为 SIZE_MAX。
xpoolvisitor类型
签名为 bool visitor(ptr object, size_t index, ptr userData)。index 是本次遍历从零开始的连续序号,不是可持久化句柄。返回 false 提前停止。
xrtPoolInit函数
使用默认 16 字节对齐初始化固定对象池。
bool xrtPoolInit(xpool* pPool, size_t iItemSize)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPool | 输出 | 非空 | 接收池 |
iItemSize | 输入 | > 0 | 每对象字节数 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 已初始化 | — |
false | 布局参数非法 | 见错误 |
错误XERR_ARGUMENT — 指针为空或参数非法XERR_RANGE — 项大小或容量为零、溢出XERR_VALUE — 对齐不是二次幂XERR_MEMORY — 槽内存分配失败
范例已编译验证
pool · 默认初始化
if ( !xrtPoolInit(&DefaultPool, sizeof(examplejob)) ) {
xrtPoolInitAligned函数
使用指定的二次幂对齐初始化固定对象池。
bool xrtPoolInitAligned(xpool* pPool, size_t iItemSize, size_t iAlignment)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPool | 输出 | 非空 | 接收池 |
iItemSize | 输入 | > 0 | 每对象字节数 |
iAlignment | 输入 | 二次幂 | 对象对齐 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 已初始化 | — |
false | 布局参数非法 | 见错误 |
错误XERR_ARGUMENT — 指针为空或参数非法XERR_RANGE — 项大小或容量为零、溢出XERR_VALUE — 对齐不是二次幂XERR_MEMORY — 槽内存分配失败
范例已编译验证
pool · 对齐初始化
if ( !xrtPoolInitAligned(&tPool, sizeof(examplejob), 32) ) {
xrtPoolInitLayout函数
使用显式对齐和每页槽数初始化固定对象池。
bool xrtPoolInitLayout(xpool* pPool, size_t iItemSize, size_t iAlignment, size_t iPageCapacity)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPool | 输出 | 非空 | 接收池 |
iItemSize | 输入 | > 0 | 每对象字节数 |
iAlignment | 输入 | 二次幂 | 对象对齐 |
iPageCapacity | 输入 | > 0 | 每页槽数 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 已初始化 | — |
false | 布局参数非法 | 见错误 |
错误XERR_ARGUMENT — 指针为空或参数非法XERR_RANGE — 项大小或容量为零、溢出XERR_VALUE — 对齐不是二次幂XERR_MEMORY — 槽内存分配失败
范例已编译验证
pool · 完整布局初始化
if ( !xrtPoolInitLayout(&LayoutPool, sizeof(examplejob),
32u, 64u) ||
(LayoutPool.PageCapacity != 64u) ) {
xrtPoolCreate函数
创建使用默认 16 字节对齐的固定对象池。
xpool* xrtPoolCreate(size_t iItemSize)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
iItemSize | 输入 | > 0 | 每对象字节数 |
错误XERR_ARGUMENT — 指针为空或参数非法XERR_RANGE — 项大小或容量为零、溢出XERR_VALUE — 对齐不是二次幂XERR_MEMORY — 槽内存分配失败
范例已编译验证
pool · 创建池
pCompact = xrtPoolCreate(8192);
xrtPoolCreateAligned函数
创建使用指定对齐的固定对象池。
xpool* xrtPoolCreateAligned(size_t iItemSize, size_t iAlignment)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
iItemSize | 输入 | > 0 | 每对象字节数 |
iAlignment | 输入 | 二次幂 | 对象对齐 |
错误XERR_ARGUMENT — 指针为空或参数非法XERR_RANGE — 项大小或容量为零、溢出XERR_VALUE — 对齐不是二次幂XERR_MEMORY — 槽内存分配失败
范例已编译验证
pool · 创建池(对齐)
pAligned = xrtPoolCreateAligned(sizeof(examplejob), 32u);
xrtPoolCreateLayout函数
创建使用显式对齐和每页槽数的固定对象池。
xpool* xrtPoolCreateLayout(size_t iItemSize, size_t iAlignment, size_t iPageCapacity)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
iItemSize | 输入 | > 0 | 每对象字节数 |
iAlignment | 输入 | 二次幂 | 对象对齐 |
iPageCapacity | 输入 | > 0 | 每页槽数 |
错误XERR_ARGUMENT — 指针为空或参数非法XERR_RANGE — 项大小或容量为零、溢出XERR_VALUE — 对齐不是二次幂XERR_MEMORY — 槽内存分配失败
范例已编译验证
pool · 创建池(完整布局)
pCreated = xrtPoolCreateLayout(sizeof(examplejob), 32, 128);
xrtPoolUnit函数
释放池持有的全部页,但不释放池结构。
void xrtPoolUnit(xpool* pPool)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPool | 输入 | 允许空 | 空 = 空操作 |
范例已编译验证
pool · 释放页
xrtPoolUnit(&tPool);
xrtPoolDestroy函数
释放池持有的全部资源和池结构。
void xrtPoolDestroy(xpool* pPool)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPool | 输入 | 允许空 | 空 = 空操作 |
范例已编译验证
pool · 销毁池
xrtPoolDestroy(pCompact);
xrtPoolAlloc函数
分配一个未初始化对象;池需要新页时可能分配内存。
ptr xrtPoolAlloc(xpool* pPool)
返回值| 返回 | 含义 | 失败时状态 |
|---|
| 非空 | 槽内存,至少按 16 字节对齐 | — |
NULL | 失败 | 见错误 |
错误XERR_ARGUMENT — 指针为空或参数非法XERR_MEMORY — 槽内存分配失败
范例已编译验证
pool · 分配对象
pReused = (examplejob*)xrtPoolAlloc(&tPool);
xrtPoolCalloc函数
分配并清零一个对象;池需要新页时可能分配内存。
ptr xrtPoolCalloc(xpool* pPool)
返回值| 返回 | 含义 | 失败时状态 |
|---|
| 非空 | 槽内存,至少按 16 字节对齐 | — |
NULL | 失败 | 见错误 |
错误XERR_ARGUMENT — 指针为空或参数非法XERR_MEMORY — 槽内存分配失败
范例已编译验证
pool · 清零分配对象
arrJob[i] = (examplejob*)xrtPoolCalloc(&tPool);
xrtPoolFree函数
安全释放活动对象,非法、跨池或重复释放均返回 false。
bool xrtPoolFree(xpool* pPool, ptr pObject)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPool | 输入 | 非空 | 目标池 |
pObject | 输入 | 本池活动对象 | 要释放的对象 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 已释放 | — |
false | 非法、跨页或重复释放 | XERR_STATE |
错误XERR_ARGUMENT — 指针为空或参数非法XERR_STATE — 重复释放、指针不属于本对象或内部状态非法
范例已编译验证
pool · 释放对象
if ( !xrtPoolFree(&tPool, pReleased) ) {
xrtPoolOwns函数
判断指针当前是否属于该池的活动对象。
bool xrtPoolOwns(const xpool* pPool, const void* pObject)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPool | 输入 | 非空 | 目标池 |
pObject | 输入 | 任意 | 待判断指针 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 是本池活动对象 | — |
false | 不是本池活动对象 | 不设错误 |
范例已编译验证
pool · 归属判断
if ( !xrtPoolOwns(&tPool, pReused) ) {
xrtPoolMark函数
标记一个活动对象为本轮可达。
bool xrtPoolMark(xpool* pPool, ptr pObject)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPool | 输入/输出 | 非空 | 目标池 |
pObject | 输入 | 本池活动对象 | 目标对象 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 已标记 | — |
false | 非本页/池活动对象 | XERR_STATE |
错误XERR_ARGUMENT — 指针为空或参数非法XERR_STATE — 重复释放、指针不属于本对象或内部状态非法
范例已编译验证
pool · 标记
if ( !xrtPoolMark(&tPool, arrJob[0]) || (xrtPoolSweep(&tPool) != 299) ) {
xrtPoolSweep函数
释放全部未标记对象,并清除幸存对象标记。
size_t xrtPoolSweep(xpool* pPool)
错误XERR_ARGUMENT — 指针为空或参数非法
范例已编译验证
pool · 清扫
if ( !xrtPoolMark(&tPool, arrJob[0]) || (xrtPoolSweep(&tPool) != 299) ) {
xrtPoolFreeMarked函数
释放全部已标记对象。
size_t xrtPoolFreeMarked(xpool* pPool)
错误XERR_ARGUMENT — 指针为空或参数非法
范例已编译验证
pool · 释放已标记
if ( !xrtPoolMark(&tPool, arrJob[0]) || (xrtPoolFreeMarked(&tPool) != 1) ) {
xrtPoolReset函数
释放全部活动对象,并按保留策略回收空页。
size_t xrtPoolReset(xpool* pPool)
错误XERR_ARGUMENT — 指针为空或参数非法
范例已编译验证
pool · 全部重置
if ( xrtPoolReset(&tPool) != 300 ) {
xrtPoolTrim函数
回收多余空页,返回真正释放的页数。
size_t xrtPoolTrim(xpool* pPool, size_t iRetainEmpty)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPool | 输入/输出 | 非空 | 目标池 |
iRetainEmpty | 输入 | — | 保留的空页数 |
错误XERR_ARGUMENT — 指针为空或参数非法
范例已编译验证
pool · 裁剪空页
if ( xrtPoolTrim(&tPool, 0) == 0 ) {
xrtPoolSetRetain函数
设置自动保留的空页数,并立即执行一次裁剪。
void xrtPoolSetRetain(xpool* pPool, size_t iRetainEmpty)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPool | 输入/输出 | 非空 | 目标池 |
iRetainEmpty | 输入 | — | 保留的空页数 |
错误XERR_ARGUMENT — 指针为空或参数非法
范例已编译验证
pool · 设置保留策略
xrtPoolSetRetain(&tPool, 2);
xrtPoolGet函数
获取固定对象池当前状态。
void xrtPoolGet(const xpool* pPool, xpoolinfo* pInfo)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPool | 输入 | 非空 | 目标池 |
pInfo | 输出 | 非空 | 接收状态快照 |
错误XERR_ARGUMENT — 指针为空或参数非法
范例已编译验证
pool · 状态查询
xrtPoolGet(&tPool, &tInfo);
xrtPoolVisit函数
访问活动对象;遍历期间只允许查询和标记,不得改变池的分配集合。
size_t xrtPoolVisit(xpool* pPool, xpoolvisitor pVisitor, ptr pUserData)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPool | 输入 | 非空 | 目标池 |
pVisitor | 输入 | 非空 | 访问回调 |
pUserData | 输入 | 任意值 | 回调数据 |
错误XERR_ARGUMENT — 指针为空或参数非法
范例已编译验证
pool · 遍历对象
if ( xrtPoolVisit(&tPool, exampleVisitJob, &iVisited) != 300 ) {
变长内存池
xmempool类型
Buckets 是 16 字节尺寸类数组,Pages 是所有小块页的有序查找索引,Large 是独立大块哈希登记表。Cutoff、ClassCount、PageCount、LargeCount、LiveCount、PeakCount、LiveBytes、PeakBytes、AllocCount 和 FreeCount 是配置与统计。其余容量、删除计数和 Flags 是内部状态。
xmempoolinfo类型
包含分界、尺寸类步长/数量、页数、小块/大块数量、实时/峰值块数、实时/峰值可用字节及累计操作次数。小块字节按尺寸类可用大小统计,不是原请求大小。
xmempoolvisitor类型
签名为 bool visitor(ptr memory, size_t size, size_t alignment, ptr userData)。size 是 xrtMemPoolSize 可查询的安全可用大小,返回 false 提前停止。
xrtMemPoolInit函数
初始化变长池,iCutoff 为零时使用默认值 1024。
bool xrtMemPoolInit(xmempool* pPool, size_t iCutoff)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPool | 输出 | 非空 | 接收池 |
iCutoff | 输入 | 0 = 1024 | 池化小块上限 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 已初始化 | — |
false | 参数非法 | XERR_ARGUMENT |
错误XERR_ARGUMENT — 指针为空或参数非法
范例已编译验证
mempool · 初始化
if ( !xrtMemPoolInit(&tPool, 128) ) {
xrtMemPoolCreate函数
创建变长池,iCutoff 为零时使用默认值 1024。
xmempool* xrtMemPoolCreate(size_t iCutoff)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
iCutoff | 输入 | 0 = 1024 | 池化小块上限 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
| 非空 | 变长池 | — |
NULL | 创建失败 | XERR_ARGUMENT / XERR_MEMORY |
错误XERR_ARGUMENT — 指针为空或参数非法XERR_MEMORY — 槽内存分配失败
范例已编译验证
mempool · 创建池
pCreated = xrtMemPoolCreate(0);
xrtMemPoolUnit函数
释放池持有的全部资源,但不释放池结构;不调用块内对象析构器。
void xrtMemPoolUnit(xmempool* pPool)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPool | 输入 | 允许空 | 空 = 空操作 |
范例已编译验证
mempool · 释放资源
xrtMemPoolUnit(&tPool);
xrtMemPoolDestroy函数
释放池持有的全部资源和池结构;不调用块内对象析构器。
void xrtMemPoolDestroy(xmempool* pPool)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPool | 输入 | 允许空 | 空 = 空操作 |
范例已编译验证
mempool · 销毁池
xrtMemPoolDestroy(pCreated);
xrtMemPoolAlloc函数
按 16 字节对齐分配内存,大小为零时仍返回至少一个可用字节。
ptr xrtMemPoolAlloc(xmempool* pPool, size_t iSize)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPool | 输入 | 非空 | 目标池 |
iSize | 输入 | — | 请求字节数 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
| 非空 | 槽内存,至少按 16 字节对齐 | — |
NULL | 失败 | 见错误 |
错误XERR_ARGUMENT — 指针为空或参数非法XERR_MEMORY — 槽内存分配失败
范例已编译验证
mempool · 分配块
pPacket = (bytes)xrtMemPoolAlloc(&tPool, 4096);
xrtMemPoolCalloc函数
分配 iCount * iSize 字节并清零;乘法溢出时失败,总大小为零时仍分配至少一个字节。
ptr xrtMemPoolCalloc(xmempool* pPool, size_t iCount, size_t iSize)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPool | 输入 | 非空 | 目标池 |
iCount | 输入 | — | 元素数量 |
iSize | 输入 | — | 每元素字节数 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
| 非空 | 槽内存,至少按 16 字节对齐 | — |
NULL | 失败 | 见错误 |
错误XERR_ARGUMENT — 指针为空或参数非法XERR_RANGE — iCount * iSize 乘法溢出XERR_MEMORY — 槽内存分配失败
范例已编译验证
mempool · 清零分配块
sText = (char*)xrtMemPoolCalloc(&tPool, 1, 24);
xrtMemPoolAllocAligned函数
按指定二次幂对齐分配,零大小仍有效,超过 16 字节对齐时走独立大块。
ptr xrtMemPoolAllocAligned(xmempool* pPool, size_t iSize, size_t iAlignment)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPool | 输入 | 非空 | 目标池 |
iSize | 输入 | — | 请求字节数 |
iAlignment | 输入 | 二次幂 | 对齐 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
| 非空 | 槽内存,至少按 16 字节对齐 | — |
NULL | 失败 | 见错误 |
错误XERR_ARGUMENT — 指针为空或参数非法XERR_VALUE — 对齐不是二次幂XERR_MEMORY — 槽内存分配失败
范例已编译验证
mempool · 对齐分配块
pAligned = (bytes)xrtMemPoolAllocAligned(&tPool, 7, 64);
xrtMemPoolRealloc函数
调整池内块大小并保留已有内容,大小为零时释放。
ptr xrtMemPoolRealloc(xmempool* pPool, ptr pMemory, size_t iSize)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPool | 输入 | 非空 | 目标池 |
pMemory | 输入 | 本池活动块或空 | 要调整的块 |
iSize | 输入 | — | 新字节数,0 = 释放 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
| 非空 | 槽内存,至少按 16 字节对齐 | — |
NULL | 失败 | 见错误 |
(pMemory 为空且大小非零时等价分配)
错误XERR_ARGUMENT — 指针为空或参数非法XERR_STATE — 重复释放、指针不属于本对象或内部状态非法XERR_MEMORY — 槽内存分配失败
范例已编译验证
mempool · 调整块大小
sText = (char*)xrtMemPoolRealloc(&tPool, sText, 80);
xrtMemPoolFree函数
安全释放池内活动块,非法、跨池或重复释放均返回 false。
bool xrtMemPoolFree(xmempool* pPool, ptr pMemory)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPool | 输入 | 非空 | 目标池 |
pMemory | 输入 | 本池活动块 | 要释放的块 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 已释放 | — |
false | 非法、跨页或重复释放 | XERR_STATE |
错误XERR_ARGUMENT — 指针为空或参数非法XERR_STATE — 重复释放、指针不属于本对象或内部状态非法
范例已编译验证
mempool · 释放块
!xrtMemPoolFree(&tPool, sText)
xrtMemPoolSize函数
返回活动块可安全使用的字节数,不属于该池时返回零。
size_t xrtMemPoolSize(const xmempool* pPool, const void* pMemory)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPool | 输入 | 非空 | 目标池 |
pMemory | 输入 | 任意 | 待查询指针 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
>= 0 | 可用字节数;0 = 不属于本池 | — |
范例已编译验证
mempool · 块大小查询
(xrtMemPoolSize(&tPool, sText) < 80) ||
xrtMemPoolOwns函数
判断指针当前是否属于该池的活动块。
bool xrtMemPoolOwns(const xmempool* pPool, const void* pMemory)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPool | 输入 | 非空 | 目标池 |
pMemory | 输入 | 任意 | 待判断指针 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 是本池活动块 | — |
false | 不是本池活动块 | 不设错误 |
范例已编译验证
mempool · 归属判断
!xrtMemPoolOwns(&tPool, sText) ||
xrtMemPoolMark函数
标记一个活动块为本轮可达。
bool xrtMemPoolMark(xmempool* pPool, ptr pMemory)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPool | 输入/输出 | 非空 | 目标池 |
pMemory | 输入 | 本池活动块 | 目标块 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 已标记 | — |
false | 非本页/池活动对象 | XERR_STATE |
错误XERR_ARGUMENT — 指针为空或参数非法XERR_STATE — 重复释放、指针不属于本对象或内部状态非法
范例已编译验证
mempool · 标记
!xrtMemPoolMark(&tPool, sText) ||
xrtMemPoolSweep函数
释放全部未标记块,并清除幸存块标记。
size_t xrtMemPoolSweep(xmempool* pPool)
错误XERR_ARGUMENT — 指针为空或参数非法
范例已编译验证
mempool · 清扫
(xrtMemPoolSweep(&tPool) != 1)
xrtMemPoolFreeMarked函数
释放全部已标记块。
size_t xrtMemPoolFreeMarked(xmempool* pPool)
错误XERR_ARGUMENT — 指针为空或参数非法
范例已编译验证
mempool · 释放已标记
(xrtMemPoolFreeMarked(&tPool) != 1) ||
xrtMemPoolReset函数
释放全部活动块,并保留每个尺寸类的一个空页。
size_t xrtMemPoolReset(xmempool* pPool)
错误XERR_ARGUMENT — 指针为空或参数非法
范例已编译验证
mempool · 全部重置
(xrtMemPoolReset(&tPool) != 2)
xrtMemPoolTrim函数
将每个尺寸类的空页裁剪到指定数量。
size_t xrtMemPoolTrim(xmempool* pPool, size_t iRetainEmptyPerClass)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPool | 输入/输出 | 非空 | 目标池 |
iRetainEmptyPerClass | 输入 | — | 每尺寸类保留空页数 |
错误XERR_ARGUMENT — 指针为空或参数非法
范例已编译验证
mempool · 裁剪空页
(void)xrtMemPoolTrim(&tPool, 0);
xrtMemPoolGet函数
获取变长池当前状态。
void xrtMemPoolGet(const xmempool* pPool, xmempoolinfo* pInfo)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPool | 输入 | 非空 | 目标池 |
pInfo | 输出 | 非空 | 接收状态快照 |
错误XERR_ARGUMENT — 指针为空或参数非法
范例已编译验证
mempool · 状态查询
xrtMemPoolGet(&tPool, &tInfo);
xrtMemPoolVisit函数
访问活动块;遍历期间只允许查询和标记,不得改变池的分配集合。
size_t xrtMemPoolVisit(xmempool* pPool, xmempoolvisitor pVisitor, ptr pUserData)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pPool | 输入 | 非空 | 目标池 |
pVisitor | 输入 | 非空 | 访问回调 |
pUserData | 输入 | 任意值 | 回调数据 |
错误XERR_ARGUMENT — 指针为空或参数非法
范例已编译验证
mempool · 遍历块
if ( xrtMemPoolVisit(&tPool, exampleVisitMemory, &iVisited) != 3 ) {
常量索引常量
以下常量在本页所属头文件中定义,语义见公共头注释。
| 常量 | 说明 |
| XPOOL_ERROR_INDEX_OUT_OF_RANGE | 见头文件注释 |
| XPOOL_ERROR_INVALID_ALIGNMENT | 见头文件注释 |
| XPOOL_ERROR_INVALID_CAPACITY | 见头文件注释 |
| XPOOL_ERROR_INVALID_POINTER | 见头文件注释 |
| XPOOL_ERROR_INVALID_SIZE | 见头文件注释 |
| XPOOL_ERROR_NOT_ALLOCATED | 见头文件注释 |
| XPOOL_ERROR_PAGE_FULL | 见头文件注释 |
| XPOOL_ERROR_VISIT_ACTIVE | 见头文件注释 |