c++自动回收对象池

发布时间:2026-03-03 02:07

C++的面向对象编程:类和对象的概念 #生活知识# #编程教程#

源码地址

https://github.com/puzzzzzzle/algorithm_study/blob/master/algorithm_cpp/src/object_pool/ObjectPool.h

自动回收裸指针的对象池

原理

c++ shared_ptr, 在析构时, 会调用deleter 策略, 一般用于 共享指针中存储数组 我们可以在这里做文章, 自定义deleter, 按照一定的策略, 选择释放内存还是回收内存 注意, 这种方式无法回收共享内存本身, 但是可以做到自动回收 适用于构造和析构消耗较大 的对象

获取对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

ObjectT *AllocWithTrunk() {
for (int i = 0; i < KEEP_SIZE / 10; ++i) {
m_reusePool.Put(new ObjectT());
}
return new ObjectT();
}
ObjectPtrT Alloc() {

ObjectT *rowPtr = m_reusePool.Take();
if (rowPtr == nullptr) {

rowPtr = AllocWithTrunk();
}
assert(rowPtr != nullptr);
m_constructor(rowPtr);
return std::shared_ptr<ObjectT>(
rowPtr, [this](ObjectT *ptr) { ReleaseObject(ptr); });
}

从池中尝试获取一个, 没拿到的话就分配一批

目前的策略是分配最大池的大小的1/10, 可以调整

分配的时候, 拿到裸指针后, 构建共享指针, 同时指定自定义的deleter

自动回收

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

void ReleaseObject(ObjectT *ptr) {
bool needReuse = true;

if (m_isStopping) {
needReuse = false;
}
if (m_reusePool.Size() > KEEP_SIZE) {
needReuse = false;
}

m_destructor(ptr);
if (needReuse) {





m_reusePool.Put(ptr);
} else {

delete ptr;
}
}
当共享指针计数为0时, 会调用deleter, 回调到我们自定义的ReleaseObject中 首先调用已定义的析构策略 按照一定的策略决定要不要回收 不回收的直接delete 回收的 再次放回池子中

释放内存池

1
2
3
4
5
6
7
8
9

~ObjectPool() {

m_isStopping = true;

while (m_reusePool.Size() > 0) {
auto *rowPtr = m_reusePool.Take();
delete rowPtr;
}
}
释放对象池时, 要销毁所有对象, 释放池子中的对象 这时候要停止回收 我们设置 m_isStopping 为true, 这时候后续的都不会被回收

自定义策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16











template <typename Object,
typename ReusePoolType = ThreadSafeQueuePoolType<Object *>,
size_t KEEP_SIZE_NUM = 10000,
typename Constructor = DefaultObjectConstructor<Object *>,
typename Destructor = DefaultObjectDestructor<Object *>>
class ObjectPool
Object: 要存储的数据类型 ReusePoolType: 用于存储池子中的对象, 默认是一个有锁的队列, 多线程安全性取决于它 KEEP_SIZE_NUM : 决定池子保存的对象的最大大小和每次分配量 Constructor : 从池子中获取一个对象前总会调用的策略 Destructor : 一个对象共享指针计数为0 时总会调用, 无论是否放回池子 构造和析构策略满足下面的格式就行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18





template <typename Object>
struct DefaultObjectConstructor {
using ObjectT = Object;
void operator()(ObjectT object) const {}
};




template <typename Object>
struct DefaultObjectDestructor {
using ObjectT = Object;
void operator()(ObjectT object) const {}
};

多线程安全

这个对象池除了 对象存储外都是多线程安全的

因此, 只要 ReusePoolType 是多线程安全的, 那池子本身就是安全的

满足如下存储器策略即可
1.

1
2
3
4
5
6

template <typename Object>
struct PoolType {
void Put(ObjectT ptr) ;
ObjectT Take();
size_t Size();
};

默认提供一个基于锁的线程安全存储器, 无锁版本可以包装一个无锁队列就行

有需要的话可以使用 moodycamel 实现的无锁安全队列 https://github.com/cameron314/concurrentqueue

1
2
3
4
5
6
7
8
9








template <typename Object>
struct ThreadSafeQueuePoolType

手动回收共享指针的对象池

线程安全性取决于 PoolType 是否是线程安全的 连 shared_ptr 也一同回收,但是需要手动调用回收函数,如果回收时, 引用计数不为1, 就会放弃回收 回收后, 原来的指针会被置为null 如果一个对象没有被 ReleaseObject 那就不会调用 Destructor, 而是直接使用默认的析构函数 需要保证析构函数和 Destructor 都可以做到资源释放, 且二次释放没有问题 用于 对象量极大, 连shared_ptr的构造和析构都是瓶颈的地方

1
2
3
4
5
6
7

template <typename Object,
typename ReusePoolType =
ThreadSafeQueuePoolType<std::shared_ptr<Object>>,
size_t KEEP_SIZE_NUM = 10000,
typename Constructor = DefaultObjectConstructor<Object *>,
typename Destructor = DefaultObjectDestructor<Object *>>
class ObjectManulPool

手动回收

使用完毕后需要手动调用TryPushBack

1
2
3
4
5
6
7
8

bool TryPushBack(ObjectPtrT &ptr) {
if (ptr.use_count() == 1) {
ReleaseObject(ptr);
ptr = nullptr;
return true;
}
return false;
}

容错机制

会检查use_count, 只回收use_count() == 1的, 回收完原来的指针会被置为nullptr 保证还在使用的对象不会被回收 对于忘记回收的, 由 shared_ptr来保证进行收尾, 不会泄漏 即使吧不是由这个对象池构造的对象进行回收也没问题, 可以兼容

网址:c++自动回收对象池 https://www.yuejiaxmz.com/news/view/1446295

相关内容

动力电池退役潮将至 电池回收行业或迎高速发展
电动车旧电池回收价格多少?电动车电池回收价格表
电动车电池如何回收?丰田汽车建立回收废旧电池机制
String a=new String(“b”+“c”)会创建几个对象?
动力电池回收产业“加速跑”
汽车动力电池回收多少钱一斤
国家对于电动汽车电池回收有哪些政策支持?
动力电池回收的“理想与现实”
推动四川新能源电池回收利用产业高质量发展
严格规范废旧动力电池回收

随便看看