对象池
前一段时间的工作中,有一项任务是检查线上代码中的动态内存分配与释放,能预先分配的统一预先分配,减少线上运行时动态分配、释放造成的性能开销。对于一些大对象来说,频繁的分配、释放会影响性能,我们可以使用对象池技术(Object Pool)来进行优化。
对象池,说白了就是一个池子,预先分配了一堆对象,原先的 new
改成从池子里取对象,delete
改成把对象放回池子。也就是池子中的对象是可以重复利用的,避免了频繁的分配、释放。
按照上面的简单思路,一个对象池的基本功能应该包括:
- 构造函数中申请一批对象
- 析构函数中释放对象
- 提供获取和回收对象的接口
Get()
和Recycle()
- 池子空了的时候支持扩容
实现起来也不难,用一个队列维护所有对象,用的时候从队列中取,回收了 push 回队列即可。不过显式的 回收 操作用起来不是很方便,忘记回收会造成资源浪费。可以考虑利用 C++ 智能指针(smart pointer)自定义删除器(deleter)来实现自动回收。
自定义智能指针的删除器
先看一个例子(这是一个错误使用智能指针的例子,只是为了展示 deleter 做了什么):
int main(int argc, char **argv) {
Object *obj1 = new Object;
std::shared_ptr<Object> p1(obj1);
std::cout << p1.use_count() << std::endl;
std::shared_ptr<Object> p2(obj1);
std::cout << p2.use_count() << std::endl;
return 0;
}
运行结果:
1
1
malloc: *** error for object 0x7f845f400340: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6
报错了,提示说释放了一个未分配的指针。这是因为 std::shared_ptr
默认的 deleter 就是 delete
,当两个 shared_ptr
实例出作用域时,执行了两次 delete obj1
,所以出错。
我们不用默认的 deleter ,试试自己定义一个 deleter 来避免第二次 delete
(再强调下,这个例子只是为了展示 deleter ,实际工作中没人会这么写的):