boost内存池的使用介绍

Boost库的pool提供了一个内存池分配器,用于管理在一个独立的、大的分配空间里的动态内存分配。

Boost库的pool主要适用于快速分配同样大小的内存块,尤其是反复分配和释放同样大小的内存块的情况。使用pool内存池主要有以下两个优点:

  

1. 能够有效地管理许多小型对象的分配和释放工作,避免了自己去管理内存而产生的内存碎片和效率低下问题。

  

2.  告别程序内存泄漏的烦恼,pool库会在内部对内存自动进行管理,避免了程序员一不小心而造成的内存泄漏问题。

pool库主要提供了四种内存池接口,分别是

pool、object_pool、singleton_pool和pool_allocator/fast_pool_allocator

1.   pool

pool是最简单也最容易使用的内存池类,可以返回一个简单数据类型(POD) 的内存指针。它

pool很容易使用,可以像C中的malloc()一样分配内存,然后随意使用。除非有特殊要求,否则不必对分配的内存调用free()释放,pool会很好地管理内存。例如:

view plaincopy to clipboardprint?

#include <boost/pool/pool.hpp>

using namespace boost;

int main()

{

pool<> pl(sizeof(int));             //一个可分配int的内存池

int *p = (int *)pl.malloc();        //必须把void*转换成需要的类型

assert(pl.is_from(p));

pl.free(p);                         //释放内存池分配的内存块

for (int i = 0;i < 100; ++i)        //连续分配大量的内存

{

pl.ordered_malloc(10);

}

}

2.  object_pool

object_pool是用于类实例(对象)的内存池,它的功能与pool类似,但会在析构时对所有已经分配的内存块调用析构函数,从而正确地释放资源。

malloc()和free()函数分别分配和释放一块类型为ElementType*的内存块,同样,可以用is_from()来测试内存块的归属,只有是本内存池分配的内存才能被free()释放。但它们被调用时并不调用类的构造函数和析构函数,也就是说操作的是一块原始内存块,里面的值是未定义的,因此我们应当尽量少使用malloc()和free()。

object_pool的特殊之处是construct()和destroy()函数,这两个函数是object_ pool的真正价值所在。construct()实际上是一组函数,有多个参数的重载形式(目前最多支持3个参数,但可以扩展),它先调用malloc()分配内存,然后再在内存块上使用传入的参数调用类的构造函数,返回的是一个已经初始化的对象指针。destory()则先调用对象的析构函数,然后再用free()释放内存块。

这些函数都不会抛出异常,如果内存分配失败,将返回0。

object_pool的用法也是很简单,我们既可以像pool那样分配原始内存块,也可以使用construct()来直接在内存池中创建对象。当然,后一种使用方法是最方便的,也是本书所推荐的。

下面的代码示范了object_pool的用法:

#include <boost/pool/object_pool.hpp>

using namespace boost;

struct demo_class                           //一个示范用的类

{

public:

int a,b,c;

demo_class(int x = 1, int y = 2, int z = 3):a(x),b(y),c(z){}

};

int main()

{

object_pool<demo_class> pl;             //对象内存池

demo_class *p = pl.malloc();            //分配一个原始内存块

assert(pl.is_from(p));       //p指向的内存未经过初始化

assert(p->a!=1 || p->b != 2 || p->c !=3);

p = pl.construct(7, 8, 9);              //构造一个对象,可以传递参数

assert(p->a == 7);

object_pool<string> pls;                //定义一个分配string对象的内存池

for (int i = 0; i < 10 ; ++i)           //连续分配大量string对象

{

string *ps = pls.construct("hello object_pool");

cout << *ps << endl;

}

}                                           //所有创建的对象在这里都被正确析构、释放内存

3.   singleton_pool

singleton_pool与pool的接口完全一致,可以分配简单数据类型(POD)的内存指针,但它是一个单件,并提供线程安全。

singleton_pool主要有两个模板类型参数(其余的可以使用缺省值)。第一个Tag仅仅是用于标记不同的单件,可以是空类,甚至是声明。第二个参数RequestedSize等同于pool构造函数中的整数requested_ size,指示pool分配内存块的大小。

singleton_pool的接口与pool完全一致,但成员函数均是静态的,因此不需要声明singleton_pool的实例 ,直接用域操作符::来调用静态成员函数。因为singleton_pool是单件,所以它的生命周期与整个程序同样长,除非手动调用release_memory()或purge_memory(),否则singleton_pool不会自动释放所占用的内存。除了这两点,singleton_pool的用法与pool完全相同。

下面的代码示范了singleton_pool的用法:

#include <boost/pool/singleton_pool.hpp>

using namespace boost;

struct pool_tag{};                                  //仅仅用于标记的空类

typedef singleton_pool<pool_tag, sizeof(int)> spl;  //内存池定义

int main()

{

int *p = (int *)spl::malloc();                      //分配一个整数内存块

assert(spl::is_from(p));

spl::release_memory();                              //释放所有未被分配的内存

}                                                       //spl的内存直到程序结束才完

singleton_pool在使用时最好使用typedef来简化名称,否则会使得类型名过于冗长而难以使用。如代码中所示:

typedef singleton_pool<pool_tag, sizeof(int)> spl;

用于标记的类pool_tag可以再进行简化,直接在模板参数列表中声明tag类,这样可以在一条语句中完成对singleton_pool的类型定义,例如:

typedef singleton_pool<struct pool_tag, sizeof(int)> spl;

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/orderd_free函数。

boost::object_pool不建议使用,可以改造后使用。

pool_allocator/fast_pool_allocator推荐使用后者。用于与STL关连。。

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!http://www.captainbed.net

原文地址:https://www.cnblogs.com/sjwudhwhhw/p/10442562.html

时间: 2024-08-29 14:59:46

boost内存池的使用介绍的相关文章

重写boost内存池

最近在写游戏服务器网络模块的时候,需要用到内存池.大量玩家通过tcp连接到服务器,通过大量的消息包与服务器进行交互.因此要给每个tcp分配收发两块缓冲区.那么这缓冲区多大呢?通常游戏操作的消息包都很小,大概几十字节.但是在玩家登录时或者卡牌游戏发战报(将整场战斗打完,生成一个消息包),包的大小可能达到30k或者更大,取决于游戏设定.这些缓冲区不可能使用glibc原始的new.delete来分配,这样可能会造成严重的内存碎片,并且效率也不高. 于是我们要使用内存池.并且是等长内存池,即每次分配的内

基于C/S架构的3D对战网络游戏C++框架 _05搭建系统开发环境与Boost智能指针、内存池初步了解

本系列博客主要是以对战游戏为背景介绍3D对战网络游戏常用的开发技术以及C++高级编程技巧,有了这些知识,就可以开发出中小型游戏项目或3D工业仿真项目. 笔者将分为以下三个部分向大家介绍(每日更新): 1.实现基本通信框架,包括对游戏的需求分析.设计及开发环境和通信框架的搭建: 2.实现网络底层操作,包括创建线程池.序列化网络包等: 3.实战演练,实现类似于CS反恐精英的3D对战网络游戏: 技术要点:C++面向对象思想.网络编程.Qt界面开发.Qt控件知识.Boost智能指针.STL算法.STL.

内存池技术介绍(图文并茂,非常清楚)

看到一篇关于内存池技术的介绍文章,受益匪浅,转贴至此. 原贴地址:http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/index6.html 6.1 自定义内存池性能优化的原理 如前所述,读者已经了解到"堆"和"栈"的区别.而在编程实践中,不可避免地要大量用到堆上的内存.例如在程序中维护一个链表的数据结构时,每次新增或者删除一个链表的节点,都需要从内存堆上分配或者释放一定的内存:在维护一个动态数组时,如果动态数组的

定长内存池之BOOST::pool

内存池可有效降低动态申请内存的次数,减少与内核态的交互,提升系统性能,减少内存碎片,增加内存空间使用率,避免内存泄漏的可能性,这么多的优点,没有理由不在系统中使用该技术. 内存池分类: 1.              不定长内存池.典型的实现有apr_pool.obstack.优点是不需要为不同的数据类型创建不同的内存池,缺点是造成分配出的内存不能回收到池中.这是由于这种方案以session为粒度,以业务处理的层次性为设计基础. 2.             定长内存池.典型的实现有LOKI.B

boost的线程池和内存池 智能指针

内存池为boost自带的 #include <boost/pool/pool.hpp> 或者另外一个开源的库: nedmalloc 一个高效率的库 线程池需要下载另外一个开源库 http://www.cnblogs.com/TianFang/archive/2007/08/23/867350.html #include <boost/thread/thread.hpp> http://blog.csdn.net/lilypp/article/details/6605246

不定长内存池之apr_pool

内存池可有效降低动态申请内存的次数,减少与内核态的交互,提升系统性能,减少内存碎片,增加内存空间使用率,避免内存泄漏的可能性,这么多的优点,没有理由不在系统中使用该技术. 内存池分类: 1.              不定长内存池.典型的实现有apr_pool.obstack.优点是不需要为不同的数据类型创建不同的内存池,缺点是造成分配出的内存不能回收到池中.这是由于这种方案以session为粒度,以业务处理的层次性为设计基础. 2.             定长内存池.典型的实现有LOKI.B

内存池、进程池、线程池

首先介绍一个概念"池化技术 ".池化技术 一言以蔽之就是:提前保存大量的资源,以备不时之需以及重复使用. 池化技术应用广泛,如内存池,线程池,连接池等等.内存池相关的内容,建议看看Apache.Nginx等开源web服务器的内存池实现. 起因:由于在实际应用当中,分配内存.创建进程.线程都会设计到一些系统调用,系统调用需要导致程序从用户态切换到内核态,是非常耗时的操作.           因此,当程序中需要频繁的进行内存申请释放,进程.线程创建销毁等操作时,通常会使用内存池.进程池.

[原创]loki库之内存池SmallObj

loki库之内存池SmallObj 介绍 loki库的内存池实现主要在文件smallobj中,顾名思义它的优势主要在小对象的分配与释放上,loki库是基于策略的方法实现的,简单的说就是把某个类通过模板参数传递给主类,比如某个对象的创建可以通过不同的创建策略进行创建,本文主要讲loki的大致实现. smallobj层次 loki.smallobj主要分四层: 应用层smallobject,重载了operator new 和operator delete,内存通过底层获取 内存分配smallobjA

Nginx 内存池管理

概述 Nginx 使用内存池对内存进行管理,内存管理的实现类似于前面文章介绍的<STL源码剖析--空间配置器>,把内存分配归结为大内存分配 和 小内存分配.若申请的内存大小比同页的内存池最大值 max 还大,则是大内存分配,否则为小内存分配. 大块内存的分配请求不会直接在内存池上分配内存来满足请求,而是直接向系统申请一块内存(就像直接使用 malloc 分配内存一样),然后将这块内存挂到内存池头部的 large 字段下. 小块内存分配,则是从已有的内存池数据区中分配出一部分内存. Nginx