内存池可有效降低动态申请内存的次数,减少与内核态的交互,提升系统性能,减少内存碎片,增加内存空间使用率,避免内存泄漏的可能性,这么多的优点,没有理由不在系统中使用该技术。
内存池分类:
1、 不定长内存池。典型的实现有apr_pool、obstack。优点是不需要为不同的数据类型创建不同的内存池,缺点是造成分配出的内存不能回收到池中。这是由于这种方案以session为粒度,以业务处理的层次性为设计基础。
2、 定长内存池。典型的实现有LOKI、BOOST。特点是为不同类型的数据结构分别创建内存池,需要内存的时候从相应的内存池中申请内存,优点是可以在使用完毕立即把内存归还池中,可以更为细粒度的控制内存块。
与变长的相比,这种类型的内存池更加通用,另一方面对于大量不同的数据类型环境中,会浪费不少内存。但一般系统主要的数据结构都不会很多,并且都是重复申请释放使用,这种情况下,定长内存池的这点小缺点可以忽略了。
Boost库的pool提供了一个内存池分配器,用于管理在一个独立的、大的分配空间里的动态内存分配。Boost库的pool主要适用于快速分配同样大小的内存块,尤其是反复分配和释放同样大小的内存块的情况。使用pool内存池主要有以下两个优点:
1. 能够有效地管理许多小型对象的分配和释放工作,避免了自己去管理内存而产生的内存碎片和效率低下问题。
2. 告别程序内存泄漏的烦恼,pool库会在内部对内存自动进行管理,避免了程序员一不小心而造成的内存泄漏问题。
pool库主要提供了四种内存池接口,分别是pool、object_pool、singleton_pool和pool_allocator/fast_pool_allocator。
1)pool
基本的定长内存池
#include <boost/pool/pool.hpp>
typedef struct student_st
{
char name[10];
int age;
}CStudent;
int main()
{
boost::pool<> student_pool(sizeof(CStudent));
CStudent * const obj=(CStudent *)student_pool.malloc();
student_pool.free(obj);
return 0;
}
pool的模版参数只有一个分配子类型,boost提供了两种default_user_allocator_new_delete/default_user_allocator_malloc_free,指明申请释放内存的时候使用new/delete,还是malloc/free,默认是default_user_allocator_new_delete。构造函数有2个参数:nrequested_size,nnext_size。nrequested_size是block的大小(因为void*保存序号,因此boost内置了block的最小值,nrequested_size过小则取内置值),nnext_size是simple_segregated_storage中内存不足的时候,申请的block数量,默认是32。最全面的实例化pool类似这样:boost::pool<boost::default_user_allocator_malloc_free> student_pool(sizeof(CStudent),255);
pool提供的函数主要有:
malloc/free 基于add_block/malloc/free实现,高效
ordered_malloc/ordered_free 基于add_ordered_block/malloc/ordered_free实现,在pool中无任何意义,切勿使用。
release_memory/purge_memory 前者释放池中未使用内存,后者释放池中所有内存。另池析构也会释放内存
2)object_pool
对象内存池,这是最失败的一个内存池设计。
#include <boost/pool/object_pool.hpp>
class A{
public:
A():data_(0){}
private:
int data_;
};
int main()
{
boost::object_pool<A> obj_pool;
A *const pA=obj_pool.construct();
obj_pool.destroy(pA);
return 0;
}
object_pool继承至pool,有两个模版参数,第一个就是对象类型,第二个是分配子类型,默认同pool是default_user_allocator_new_delete。构造函数参数只有nnext_size,意义以及默认值同pool。最全面的实例化object_pool类似这样:boost::pool<A,boost::default_user_allocator_malloc_free> obj_pool(255);
object_pool提供的函数主要有(继承至父类的略): malloc/free 复写pool的malloc/free,add_ordered_block/malloc/ordered_free实现
construct/destroy 基于本类的malloc/free实现,额外调用默认构造函数和默认析构函数。
~object_pool 单独拿出这个说下,若析构的时候有对象未被destroy,可以检测到,释放内存前对其执行destroy
为什么boost::object_pool要设计成这样?能调用构造函数和析构函数显然不是boost::object_pool类设计的出发点,因为构造函数只能执行默认构造函数(首次发表错误:可以调用任意的构造函数,参见代码文件:boost/pool/detail/pool_construct.inc和boost/pool/detail/pool_construct_simple.inc,感谢eXile指正),近似于无,它的重点是内存释放时候的清理工作,这个工作默认的析构函数就足够了。apr_pool内存池中就可以注册内存清理函数,在释放内存的时刻执行关闭文件描述符、关闭socket等操作。boost::object_pool也想实现同样的功能,因此设计了destroy这个函数,而同时为了防止用户遗漏掉这个调用,而又在内存池析构的时候进行了检测回收。为了这个目的而又不至于析构object_pool的时间复杂度是O(n平方),boost::object_pool付出了沉重的代价,在每次的destoy都执行排序功能,时间复杂度O(n),最后析构的时间复杂度是O(n),同样为了这个目的,从simple_segregated_storage增加了add_ordered_block/ordered_free,pool增加了ordered_malloc/ordered_free等累赘多余的功能。
基于上面讨论的原因,boost::object_pool被设计成了现在的样子,成了一个鸡肋类。类的设计者似乎忘记了内存池使用的初衷,忘记了内存池中内存申请释放的频率很高,远远大于内存池对象的析构。如果你依然想使用类似于此的内存清理功能,可以在boost::object_pool上修改,不复写malloc/free即可,重写object_pool的析构,简单释放内存就好,因此析构object_pool前不要忘记调用destroy,这也是使用placement new默认遵守的规则,或者保持以前的析构函数,牺牲析构时的性能。placement new的作用是为已经申请好的内存调用构造函数,使用流程为(1)申请内存buf(2)调用placement new:new(buf)construtor()(3)调用析构destructor()(4)释放内存buf。#include<new>可以使用placement new。
3)singleton_pool
pool的加锁版本。
#include <boost/pool/singleton_pool.hpp>
typedef struct student_st
{
char name[10];
int age;
}CStudent;
typedef struct singleton_pool_tag{}singleton_pool_tag;
int main()
{
typedef boost::singleton_pool<singleton_pool_tag,sizeof(CStudent)> global;
CStudent * const df=(CStudent *)global::malloc();
global::free(df);
return 0;
}
singleton_pool为单例类,是对pool的加锁封装,适用于多线程环境,其中所有函数都是静态类型。它的模版参数有5个,tag:标记而已,无意义;RequestedSize:block的长度;UserAllocator:分配子,默认还是default_user_allocator_new_delete;Mutex:锁机制,默认值最终依赖于系统环境,linux下是pthread_mutex,它是对pthread_mutex_t的封装;NextSize:内存不足的时候,申请的block数量,默认是32。最全面的使用singleton_pool类似这样:typedef boost::singleton_pool<singleton_pool_tag,sizeof(CStudent),default_user_allocator_new_delete,details::pool::default_mutex,200> global;
它暴露的函数和pool相同。
4)pool_allocator/fast_pool_allocator
stl::allocator的替换方案。两者都是基于singleton_pool实现,实现了stl::allocator要求的接口规范。两者的使用相同,区别在于pool_allocator的内部实现调用了ordered_malloc和ordered_free,可以满足对大量的连续内存块的分配请求。fast_pool_allocator 的内部实现调用了malloc和free,比较适合于一次请求单个大内存块的情况,但也适用于通用分配,不过具有一些性能上的缺点。因此推荐使用后者。
#include <boost/pool/pool_alloc.hpp>
#include <vector>
typedef struct student_st
{
char name[10];
int age;
}CStudent;
int main()
{
std::vector<CStudent *,boost::fast_pool_allocator<CStudent *> > v(8);
CStudent *pObj=new CStudent();
v[1]=pObj;
boost::singleton_pool<boost::fast_pool_allocator_tag,sizeof(CStudent *)>::purge_memory();
return 0;
}
fast_pool_allocator的模版参数有四个:类型,分配子,锁类型,内存不足时的申请的block数量,后三者都有默认值,不再说了。它使用的singleton_pool的tag是boost::fast_pool_allocator_tag。
总结:boost::pool小巧高效,多多使用,多线程环境下使用boost::singleton_pool,不要使用两者的ordered_malloc/ordered_free函数。boost::object_pool不建议使用,可以改造后使用。pool_allocator/fast_pool_allocator推荐使用后者。
参考资料:
boost官方网站: http://www.boost.org/
分享到:
相关推荐
10. **存档的输入/输出流**:Boost.Serialization库可以与任何支持`std::ios_base`的输出和输入流配合,包括文件流、内存流、甚至是网络流。 11. **序列化和异常安全**:Boost.Serialization库设计为异常安全,如果...
【作品名称】:基于Numpy和Boost::Python实现的矩量法 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【项目介绍】: 基于Numpy和...
### GlusterFS 之内存池(mem-pool)实现原理及代码详解 #### 一、引言 GlusterFS是一款高性能、可扩展的分布式文件系统,适用于存储大规模数据集。其设计之初即考虑到了高性能与高可用性的需求,因此在内部实现上...
例如,`boost::asio`用于网络编程,`boost::thread`和`boost::mutex`则涉及多线程同步,`boost::filesystem`提供文件系统操作,`boost::regex`处理正则表达式,`boost::date_time`管理日期和时间,还有`boost::...
通过分析`mem_pool`中的源码,我们可以了解到内存池的具体实现细节,包括内存的分配策略、内存块的管理方式以及如何处理内存碎片等。如果你对内存管理有兴趣,深入研究这个源码将会是一个很好的学习机会。 总的来说...
### 简单内存池模块详细设计 #### 定义内存池性能优化的原理 内存池作为一种优化技术,主要用于提高程序在频繁分配和释放小块内存时的效率。相较于使用系统提供的内存管理函数(如`new/delete`或`malloc/free`),...
内存池是一种优化内存分配策略的技术,它通过预先分配一大块连续的内存,并将其划分为多个固定大小的小块,以供程序动态分配时使用。这种方式可以避免频繁地进行系统级的内存分配与释放,从而减少系统开销,提高程序...
在 IT 领域,Boost.Asio 是一个广泛使用的库,尤其在开发网络应用程序时,它为异步 TCP 通信提供了强大的支持。本教程将详细探讨如何在 Ubuntu 操作系统上利用 Boost.Asio 实现高效的异步 TCP 通信。Ubuntu 的稳定性...
需要包含boost的路径为: include path: F:\boost_1_53_0 lib path:F:\boost_1_53_0\stage\lib 需要预定义的宏: _WIN32_WINNT=0x0700 在程序里写的接收ip为192.168.1.206,端口为 9002
Boost Pool提供了多种类型的内存池,如singleton_pool和object_pool,可以根据需求选择合适的内存管理策略。使用内存池可以显著提高内存分配和释放的效率,减少系统调用次数,降低程序的内存开销。 shared_ptr是C++...
定长内存池也叫做对象池,在创建对象池时,对象池可以根据传入的对象类型的大小来实现“定长”,因此我们可以通过使用模板参数来实现“定长”,比如创建定长内存池时传入的对象类型是 int,那么该内存池就只支持 4 ...
4. 销毁内存池:在程序结束时,如果不再需要内存池,可以调用销毁函数,将内存池的内存全部释放回系统。 三、多线程支持 在多线程环境中,为了保证内存池的线程安全,我们需要考虑以下几点: 1. 互斥锁:在分配和...
- **Boost库概述**:Boost是一个免费且开源的跨平台C++库集合,旨在提供高质量的通用组件。 - **历史与发展**:自1995年以来不断发展,成为C++社区中最受尊敬的项目之一。 - **特性与优势**:包括但不限于类型安全、...
C++与MySQL数据库之间的通信是通过特定的API接口实现的,而在实际的大型系统中,为了提高数据库操作的效率和性能,通常会采用连接池(Connection Pool)技术。本资源包含了一个可编译运行的C++ MySQL连接池示例,这...
eCos内存管理主要分为两种类型:变长内存池和定长内存池。 ##### 变长内存池 变长内存池根据应用程序请求的尺寸动态分配内存。这种机制使得内存分配更加灵活,能够满足不同大小的内存需求。然而,它也可能引入更多...
在Unity引擎中,每当创建一个新的GameObject时,系统会分配内存并初始化相关组件,而销毁对象时,这些资源并不会立即释放,而是被放入内存池等待垃圾回收。这个过程在大规模的游戏场景中可能会导致性能下降,因为...
内存池是一种优化内存分配策略的技术,它在程序启动时预先分配一大块连续的内存空间,然后根据需要从中划分出小块内存供程序使用,而不是每次内存申请都直接向操作系统申请。这种方式可以减少内存碎片,提高内存分配...
- **内存池(Memory Pool)**:包含多个内存块,用于统一管理所有的内存资源。 ##### 3.2 内存单元的管理 为了方便管理和使用内存单元,通常会定义一个结构体来记录每个内存单元的状态,例如: ```cpp typedef ...
《PoolManager对象池插件详解及实战应用》 在Unity游戏开发中,高效管理资源是提升游戏性能的关键一环。PoolManager对象池插件正是为了实现这一目标而设计的,它通过复用游戏对象,避免频繁创建和销毁,极大地提高...
Linux内存池的数据结构定义在`include/linux/mem_pool.h`文件中。其中,内存池的主要数据结构如下所示: ```c typedef struct mempool_s { spinlock_t lock; // 互斥锁 int min_nr; // elements 数组中的成员数量...