pool库概述

如果之前学过操作系统的内存管理机制和内存分配算法等知识,那么就了解“内存池”的概念。

简单地说,内存池预先分配了一块大的内存空间,然后就可以在其中使用某种算法实现高效快速的自定制内存分配。

boost.pool库基于简单分配存储思想实现了一个快速、紧凑的内存池库,不仅能够管理大量的对象,而且还可以被用作STL的内存分配器。它近似于一个小型的垃圾回收机制,在需要大量地分配/释放小对象时很有效,并且完全不需要考虑delete。

pool库包含四个部分,最简单地pool、分配类实例的object_pool、单件内存池singleton_pool和可用于标准库的pool_alloc。

1:pool

pool是最简单也最容易使用的内存池类,可以返回一个简单数据类型(POD,Plain Old Data)的内存指针,它位于命名空间boost,为了使用pool组件,需要包含头文件<boost/pool/pool.hpp>。

类摘要:

template<typename UserAllocator >
class pool{
public:
explicit pool(size_type requested_size);
~pool();
size_type get_requested_size() const;
void *malloc();
void *ordered_malloc();
void *ordered_malloc(size_type n);
bool is_from(void *chunk) const;
void free(void *chunk);
void ordered_free(void *chunk);
void free(void *chunks,size_type n);
void ordered_free(void *chunks,size_type n);
bool release_memory();
bool purge_memory();
};

操作函数

pool的模板类型参数UserAllocator 是一个用户定义的内存分配器,它实现了特定的内存分配算法,通常可以直接用默认的default_user_allocator_new_delete。

pool的构造函数接受一个size_type类型的整数requested_size,指示每次pool分配内存块的大小(而不是pool内存池的大小),这个值可以用get_requested_size()获得。pool会根据需要自动地向系统申请或归还使用的内存,在析构时,pool将自动释放它所持有的所有内存块。

成员函数malloc()和ordered_malloc()的行为很类似C中的全局函数malloc(),用void*指针返回从内存池中分配的内存块,大小为构造函数中指定的requested_size。如果内存分配失败,函数将返回0,不会抛出异常。malloc()从内存池中任意分配一个内存块,而ordered_malloc()则在分配的同时合并空闲块链表。ordered_malloc()带参数的形式还可以连续分配n块的内存。分配后的内存块可以用is_from()函数测试是否是从这个内存池分配过去的。

与malloc()对应的一组函数是free(),用来手工释放之前分配的内存块,这些内存块必须是从这个内存池分配出去的(is_from(chunk) == true)。一般情况内存池会自动管理内存分配,不应该调用free()函数,除非你认为内存池的空间已经不足,必须释放已经分配的内存。

最后还有两个成员函数:release_memory()让内存池释放所有未被分配的内存,但已分配的内存块不受影响;purge_memory()则强制释放pool所持有的所有内存,不管内存块是否被使用。实际上,pool的析构函数就是调用的purge_memory()。这两个函数一般情况下也不应该手工调用。

使用示例:

#include <iostream>
#include <boost/pool/pool.hpp>
using namespace boost;
using namespace std;
int main(){
//一个可分配int的内存池
pool<> pl(sizeof(int));
//必须把void*转换成需要的类型
int *p = (int *)pl.malloc();
assert(pl.is_from(p));
cout << "pl is allocated from pool." << endl;
//释放内存池分配的内存块
pl.free(p);
cout << "Free memory pool of the allocated memory block" << endl;
//连续分配大量的内存
for(int i = 0; i < 100; ++i)
pl.ordered_malloc(10);
cout << "allocated a large of memory" << endl
<< "now free all memory..." << endl;
}

运行结果:

pl is allocated from pool.
Free memory pool of the allocated memory block
allocated a large of memory
now free all memory...

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

因为pool在分配内存失败的时候不会抛出异常,所以实际编写代码时应该检查malloc()函数返回的指针,以防止空指针错误。不过这种情况极少出现。

int *p = (int *)pl,malloc();

if(p != NULL);

关于pool<>需要注意的是:它只能作为普通数据类型如int、double、float等的内存池,不能应用于复杂的类和对象,因为它只负责分配内存,不调用构造函数。

object_pool

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

类摘要:

template<typename ElementType>
class object_pool:protected pool{
public:
object_pool();
~object_pool();
element_type *malloc();
void free(element_type *p);
bool is_from(element_type *p) const;
element_type * construct();
void destory(element_type *p);
};

操作函数

object_pool是pool的子类,但它使用的是保护继承,因此不能使用pool的接口。

object_pool的模板参数类型参数ElementType指定了object_pool 要分配的元素类型,要求其析构函数不能抛出异常。一旦在模板中指定了类型,object_pool对象就不能再用于分配其他类型的对象。

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

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

使用示例:

#include <iostream>
#include <boost/pool/object_pool.hpp>
using namespace std;
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));
cout << "ok,allocated from pl..." << endl;
//p指向的内存未经过初始化
assert(p->a != 1 || p->b != 2 || p->c != 3);
//构造一个对象,可以传递参数
p = pl.construct(7,8,9);
assert(p->a == 7);
cout << p->a << " " << p->b << " " << p->c << endl;
//定义一个分配string对象的内存池
object_pool<string> pls;
//连续分配大量string对象
for(int i = 0; i < 10; ++i){
string *ps = pls.construct("hello object_pool");
cout << *ps << endl;
}
//所有创建的对象在这里都被正确地析构、释放内存
}

singleton_pool

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

由于目前Boost还未提供标准的单件库,singleton_pool在其内部实现了一个较简单、泛型的单件类,保证在main()函数运行之前就创建单件。

类摘要:

template< typename Tag,unsigned RequestedSize >
class singleton_pool{
public:
static bool is_from(void *ptr);
static void *malloc();
static void *ordered_malloc();
static void *ordered_malloc(size_type n);
static void free(void *ptr);
static void ordered_free(void *ptr);
static void free(void *ptr,std::size_type n);
static bool release_memory();
static bool purge_memory();
};

singleton_pool主要有两个模板类型参数(其余的可以使用缺省值)。第一个Tag仅仅是用于标记不同的单件,可以是空类,甚至是声明(这个用法还被用于boost.exception)。

第二个参数RequestedSize等同于pool构造函数中的整数requested_size,指示pool分配内存块的大小。

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

pool_alloc

pool_alloc提供了两个可以用于标准容器模板参数的内存分配器,分别是pool_alloc和fast_pool_allocator,它们的行为与之前的内存池类有一点不同-----当内存分配失败时会抛出异常std::bad_alloc,除非特别的需求,我们应该总使用STL实现自带的内存分配器,使用pool_alloc需要经过仔细测试,以保证它与容器可以共同工作。

使用示例:

#include <iostream>
#include <vector>
#include <boost/pool/pool_alloc.hpp>
using namespace std;
using namespace boost;
int main(){
//使用pool_allocator代替标准容器默认的内存分配器
vector<int,pool_allocator<int> > v;
//vector将使用新的分配器良好工作
v.push_back(10);
cout << v.size() << endl;
}

[内存管理]内存池pool库相关推荐

  1. LwIP 之六 详解动态内存管理 内存池(memp.c/h)

      该文主要是接上一部分LwIP 之 详解动态内存管理 内存堆(mem.c/h),该部分许多内容需要用到上一篇的内容.该部分主要是详细介绍LwIP中的动态内存池.整个内存池的实现相较于内存堆来说,还是 ...

  2. 内存管理-内存池的实现

    内存池的实现 1 前言 2 内存池的原理 2.1 内存利用链表进行管理 2.2 分配固定大小 2.3 按块进行内存管理 3 内存池的实现 3.1 内存池的创建 3.2 内存池的销毁 3.3 内存分配 ...

  3. LwIP 之五 详解动态内存管理 内存堆(mem.c/h)

    写在前面   目前网上有很多介绍LwIP内存的文章,但是绝大多数都不够详细,甚至很多介绍都是错误的!无论是代码的说明还是给出的图例,都欠佳!下面就从源代码,到图例详细进行说明.   目前,网络上多数文 ...

  4. dpdk内存管理——内存初始化

    *说明:本系列博文源代码均来自dpdk17.02* 1.1内存初始化 1.1.1 hugepage技术 hugepage(2M/1G..)相对于普通的page(4K)来说有几个特点: (1) huge ...

  5. BOOST内存管理(二) --- boost::pool

    Boost库的pool提供了一个内存池分配器,用于管理在一个独立的.大的分配空间里的动态内存分配.Boost库的pool主要适用于快速分配同样大小的内存块,尤其是反复分配和释放同样大小的内存块的情况. ...

  6. 内存管理 浅析 内存管理/内存优化技巧

    内存管理 浅析 下列行为都会添加一个app的内存占用: 1.创建一个OC对象: 2.定义一个变量: 3.调用一个函数或者方法. 假设app占用内存过大.系统可能会强制关闭app,造成闪退现象,影响用户 ...

  7. 内存管理 内存优化技巧 浅析

    内存管理 浅析 下列行为都会增加一个app的内存占用: 1.创建一个OC对象: 2.定义一个变量: 3.调用一个函数或者方法. 如果app占用内存过大,系统可能会强制关闭app,造成闪退现象,影响用户 ...

  8. 纯干货,linux内存管理——内存管理架构(建议收藏)

    一.内存管理架构 内存管理子系统架构可以分为:用户空间.内核空间及硬件部分3个层面,具体结构如下所示: 1.用户空间:应用程序使用malloc()申请内存资源/free()释放内存资源. 2.内核空间 ...

  9. Linux内存管理内存映射以及通过反汇编定位内存错误问题

    提到C语言,我们知道C语言和其他高级语言的最大的区别就是C语言是要操作内存的! 我们需要知道--变量,其实是内存地址的一个抽像名字罢了.在静态编译的程序中,所有的变量名都会在编译时被转成内存地址.机器 ...

最新文章

  1. linux程序计数器,如何在C中打印程序计数器的确切值
  2. SFB 项目经验-13-为某上市企业仅安装Skype for Business 2016(图解)
  3. linux 定时每天执行php,linux下使用cronjob定时执行php脚本
  4. (021)java后台开发之HttpServletRequest
  5. C 语言编程 — 编程规范
  6. iBatis.Net系列(二)-项目类型
  7. 软件工程基础-结对项目-WordCount(单词计数)
  8. Jerry文章《浅谈Java和SAP ABAP的静态代理和动态代理,以及ABAP面向切面编程的尝试一文的源代码》
  9. devexpress卸载不干净_最好用的卸载工具,清理彻底,专治各种流氓软件
  10. sys.dm_exec_query_stats的total_worker_time的单位是微秒还是毫秒
  11. QML笔记-使用connect界面数据交互(qml中Designer使用)
  12. Python从命令行参数和配置文件获取信息
  13. c语言向自定数组_C语言怎么向自定义函数中传入一个数组,处理完再返回新的数组?...
  14. Java虚拟机自动内存管理
  15. fileziller 恢复 站点管理器 内的ftp帐号方法
  16. 如何使用代码给菜单增加图标
  17. matlab 求极小值 一维优化,MATLABoptimization
  18. QT第三方串口类Win_QextSerialPort,串口工具插拔后无法继续使用问题
  19. 基于JSP的图书管理系统
  20. 快速原型制造_快速原型初学者指南

热门文章

  1. Notepad++更改背景颜色(护眼色)
  2. 【Web开发】Python实现Web服务器(Ubuntu下Flask使用MySQL数据库)
  3. 制作自己的ctpn数据集
  4. linux上安装java失败,Linux下安装jdk失败怎么办
  5. 关于Linux下的复制命令保持文件的属性和链接文件的依赖性等
  6. 【以太网硬件九】1000base-X是什么?
  7. 成功解决OBS中的回音问题
  8. 【玩计算机才是最好的出路】
  9. 乌克兰证券委员会主席支持认可加密货币作为金融工具的合法地位
  10. 计蒜客信息学入门赛 #16--B