zoukankan      html  css  js  c++  java
  • boost内存池的使用介绍

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

     

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

      

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

      

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

          

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

    poolobject_poolsingleton_poolpool_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_poolpool的接口完全一致,可以分配简单数据类型(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标记而已,无意义;

    RequestedSizeblock的长度;

    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相同。

    4pool_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_pooltagboost::fast_pool_allocator_tag

    总结:

    boost::pool小巧高效,多多使用

    boost::singleton_pool多线程环境下使用,不要使用两者的ordered_malloc/orderd_free函数。

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

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

  • 相关阅读:
    VC++6.0在win8.1系统下运行失败的解决办法
    oracle赋值问题(将同一表中某一字段赋值给另外一个字段的语句)
    Myeclipse 2014破解教程
    关于js赋值给input解析
    java时间格式
    Idea报错Check $M2_HOME environment variable and mvn script match.
    新博客
    理解jquery的$.extend()、$.fn和$.fn.extend()
    在vs code中使用ftp-sync插件实现客户端与服务器端代码的同步
    js字符串倒序
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13318405.html
Copyright © 2011-2022 走看看