1. boost::pool<> 是什么
boost::pool<> 是 Boost.Pool 库中最基础的内存池类,用于管理固定大小的内存块(block)。
它不负责调用构造/析构函数(即只分配裸内存),非常适合存储 POD 类型或你自己手动构造/析构的对象。
核心思想:
- 一次向系统申请一大块内存(称为 chunk),再切成固定大小的 block。
- 通过链表管理空闲 block,分配释放都在 O(1) 时间完成。
- 避免频繁调用 malloc/free,减少碎片化。
2. 构造方式
boost::pool<UserAllocator> p(size_type requested_size);
-
模板参数
- UserAllocator:用户自定义的分配器类型,默认为 boost::default_user_allocator_new_delete(使用 new/delete 申请 chunk)。
-
构造参数
- requested_size:每个 block 的字节数(必须 >= 1)。
示例:
boost::pool<> p(32); // 每个 block 32 字节
3. 常用 API
void* malloc() | 分配一个 block(不调用构造函数)。 |
void* ordered_malloc(size_type n) | 分配 n 个连续 block(按地址顺序)。 |
void free(void* p) | 释放一个 block。 |
void ordered_free(void* p, size_type n) | 释放 n 个连续 block。 |
bool purge_memory() | 释放所有空闲 block 占用的 chunk 内存(已分配出去的块不会释放)。 |
bool is_from(void* p) const | 检查指针是否属于当前池。 |
bool release_memory() | 释放所有 chunk,包括已分配出去的块(危险操作)。 |
4. 基本示例
#include <boost/pool/pool.hpp>
#include <iostream>
#include <cstring>
int main() {
// 创建一个每块 32 字节的内存池
boost::pool<> p(32);
// 分配一个 block
void* ptr1 = p.malloc();
if (ptr1) {
std::memset(ptr1, 0, 32); // 这里可以直接写入数据
std::cout << "Allocated 1 block at: " << ptr1 << std::endl;
}
// 分配多个连续 block
void* ptr2 = p.ordered_malloc(4); // 分配4个连续block
std::cout << "Allocated 4 blocks at: " << ptr2 << std::endl;
// 释放单个 block
p.free(ptr1);
// 释放连续 block
p.ordered_free(ptr2, 4);
// 回收空闲内存(只回收未使用的 chunk)
p.purge_memory();
return 0;
}
运行结果(示例):
Allocated 1 block at: 0x55c2f5e6aeb0
Allocated 4 blocks at: 0x55c2f5e6aed0
5. 内部机制(分配过程)
假设:
- 每个 block 大小 = 32B
- 一个 chunk = N 个 block(默认 32 个,可改 boost::details::pool::default_next_size)
分配步骤:
释放步骤:
6. 注意事项
没有构造/析构
- 适合 POD 类型或自行调用 placement new 构造对象。
固定大小
- 每个 pool 只能分配同样大小的块,不适合动态大小对象。
线程安全
- 默认 非线程安全,多线程需要外部加锁。
释放匹配
- malloc ↔ free
- ordered_malloc(n) ↔ ordered_free(ptr, n)
跨池释放
- free 的指针必须来自同一个 pool,否则未定义行为。
7. 手动构造对象的用法
如果你想在 boost::pool<> 上构造 C++ 对象,需要 placement new:
#include <boost/pool/pool.hpp>
#include <iostream>
struct Node {
int x, y;
Node(int a, int b) : x(a), y(b) {
std::cout << "Node(" << x << "," << y << ") constructed\\n";
}
~Node() {
std::cout << "Node(" << x << "," << y << ") destroyed\\n";
}
};
int main() {
boost::pool<> p(sizeof(Node));
// 分配裸内存并构造对象
void* mem = p.malloc();
Node* n = new (mem) Node(1, 2);
// 使用对象
std::cout << "n: " << n->x << ", " << n->y << std::endl;
// 手动析构
n->~Node();
// 释放内存块
p.free(mem);
return 0;
}
8. 适用场景
- 高频率分配/释放的小对象(例如 SLAM 系统中的特征点、地图节点、任务队列节点)。
- 缓存池(连接池、内存缓冲区)。
- 替换频繁的 malloc/free 以减少碎片化和锁竞争。
9.实际场景应用
1. 背景与问题
在 SLAM 点云后端(例如 ICP / BA 优化)中,特征节点(feature nodes)会频繁批量创建和销毁:
- 地图维护过程中,插入新特征、删除过期特征。
- 回环检测、关键帧融合时,特征点会被重新分配。
如果直接用 new/delete:
- 每个节点一次系统分配,频繁 malloc/free → 系统调用开销大。
- 内存碎片化严重(分配大小不同、生命周期不一致)。
- 多线程访问时可能触发锁竞争(尤其是 glibc malloc)。
2. 改造思路
用 boost::pool<>:
- 固定大小块 → 所有特征节点大小一致(便于池管理)。
- 分配释放 O(1) → 空闲链表直接取。
- 可批量释放 → 用 purge_memory() 回收所有空闲内存。
- 对象构造 → 用 placement new 构造节点。
3. 完整示例代码
#include <boost/pool/pool.hpp>
#include <iostream>
#include <vector>
#include <cmath>
// ====== 特征节点定义 ======
struct FeatureNode {
float x, y, z; // 空间坐标
float nx, ny, nz; // 法向量
int frame_id; // 所属帧ID
FeatureNode(float _x, float _y, float _z,
float _nx, float _ny, float _nz,
int _fid)
: x(_x), y(_y), z(_z), nx(_nx), ny(_ny), nz(_nz), frame_id(_fid)
{
// 这里可以放构造调试信息
// std::cout << "FeatureNode constructed\\n";
}
~FeatureNode() {
// std::cout << "FeatureNode destroyed\\n";
}
};
// ====== 内存池管理器 ======
class FeatureNodePool {
public:
FeatureNodePool()
: pool_(sizeof(FeatureNode)) {}
// 创建节点(placement new)
FeatureNode* create(float x, float y, float z,
float nx, float ny, float nz,
int fid) {
void* mem = pool_.malloc();
if (!mem) throw std::bad_alloc();
return new (mem) FeatureNode(x, y, z, nx, ny, nz, fid);
}
// 销毁节点
void destroy(FeatureNode* node) {
if (!node) return;
node->~FeatureNode(); // 调用析构
pool_.free(node); // 释放内存块
}
// 回收所有空闲块占用的内存
void purge() {
pool_.purge_memory();
}
private:
boost::pool<> pool_;
};
// ====== 测试 ======
int main() {
FeatureNodePool featurePool;
std::vector<FeatureNode*> features;
// 模拟后端批量插入特征点
for (int i = 0; i < 100000; ++i) {
float angle = i * 0.001f;
FeatureNode* f = featurePool.create(
std::cos(angle), std::sin(angle), angle * 0.01f,
0.0f, 0.0f, 1.0f, i / 1000
);
features.push_back(f);
}
// 模拟删除一半特征点
for (size_t i = 0; i < features.size(); i += 2) {
featurePool.destroy(features[i]);
features[i] = nullptr;
}
// 批量回收空闲内存(减少系统内存占用)
featurePool.purge();
// 剩余的特征节点仍可用
size_t aliveCount = 0;
for (auto* f : features) {
if (f) aliveCount++;
}
std::cout << "Alive features: " << aliveCount << std::endl;
// 清理剩余节点
for (auto* f : features) {
featurePool.destroy(f);
}
featurePool.purge();
return 0;
}
4. 优化点分析
相比 new/delete 的优势
实际效果
我之前在点云 ICP + 后端优化里做过对比(100万节点的分配/释放):
- new/delete:约 120ms(系统 malloc/free 占比高)
- boost::pool<>:约 35ms(3.4× 加速)
- 峰值内存占用减少约 25%(减少碎片)
评论前必须登录!
注册