C++内存管理变革(4): boost::object_pool

言归正传。我们在内存池(MemPool)技术详解已经介绍了boost::pool组件。从内存管理观念的变革来看,这是是一个传统的MemPool组件,尽管也有一定的改进(但只是性能上的改进)。但boost::object_pool不同,它与我在C++内存管理变革强调的观念非常吻合。可以认为,boost::object_pool是一种不通用的gc allocator组件。

我已经多次提出gc allocator的概念。这里仍然需要强调一下,所谓gc allocator,是指具垃圾回收能力的allocator。C++内存管理变革(1) 中我们引入了这个概念,但是没有明确gc allocator一词。

boost: object_pool内存管理观念

boost::object_pool的了不起之处在于,这是C++从库的层次上头一次承认,程序员在内存管理上是会犯错误的,由程序员来确保内存不泄漏是困难的。boost::object_pool允许你忘记释放内存。我们来看一个例子:

class X { … };

    void func()
    {
        boost::object_pool<X> alloc;

        X* obj1 = alloc.construct();
        X* obj2 = alloc.construct();
        alloc.destroy(obj2);
    }

如果boost::object_pool只是一个普通的allocator,那么这段代码显然存在问题,因为obj1的析构函数没有执行,申请的内存也没有释放。

但是这段代码是完全正常的。是的,obj1的析构确实执行了,所申请内存也被释放了。这就是说,boost::object_pool既支持你手工释放内存(通过主动调用object_pool::destroy),也支持内存的自动回收(通过object_pool::~object_pool析构的执行)。这正符合gc allocator的规格。

注:内存管理更好的说法是对象管理。内存的申请和释放更确切的说是对象的创建和销毁。但是这里我们不刻意区分这两者的差异。

boost: object_pool与AutoFreeAlloc

我们知道,AutoFreeAlloc不支持手工释放,而只能等到AutoFreeAlloc对象析构的时候一次性全部释放内存。那么,是否可以认为boost::object_pool是否比AutoFreeAlloc更加完备呢?

其实不然。boost::object_pool与AutoFreeAlloc都不是完整意义上的gc allocator。AutoFreeAlloc因为它只能一次性释放,故此仅仅适用特定的用况。然而尽管AutoFreeAlloc不是普适的,但它是通用型的gc allocator。而boost::object_pool只能管理一种对象,并不是通用型的allocator,局限性其实更强。

boost: object_pool的实现细节

大家对boost::object_pool应该已经有了一个总体的把握。现在,让我们深入到object_pool的实现细节中去。

在内存池(MemPool)技术详解中,我们介绍boost::pool组件时,特意提醒大家留意pool::ordered_malloc/ordered_free函数。事实上,boost::object_pool的malloc/construct, free/destroy函数调用了pool::ordered_malloc, ordered_free函数,而不是pool::malloc, free函数。

让我们解释下为什么。

其实这其中的关键,在于object_pool要支持手工释放内存和自动回收内存(并自动执行析构函数)两种模式。如果没有自动析构,那么普通的MemPool就足够了,也就不需要ordered_free。既然有自动回收,同时又存在手工释放,那么就需要区分内存块(MemBlock)中哪些结点(Node)是自由内存结点(FreeNode),哪些结点是已经使用的。对于哪些已经是自由内存的结点,显然不能再调用对象的析构函数。

我们来看看object_pool::~object_pool函数的实现:

template <typename T, typename UserAllocator>
object_pool<T, UserAllocator>::~object_pool()
{
  // handle trivial case
  if (!this->list.valid())
    return;

  details::PODptr<size_type> iter = this->list;
  details::PODptr<size_type> next = iter;

  // Start ’freed_iter’ at beginning of free list
  void * freed_iter = this->first;

  const size_type partition_size = this->alloc_size();

  do
  {
    // increment next
    next = next.next();

    // delete all contained objects that aren’t freed

    // Iterate ’i' through all chunks in the memory block
    for (char * i = iter.begin(); i != iter.end(); i += partition_size)
    {
      // If this chunk is free
      if (i == freed_iter)
      {
        // Increment freed_iter to point to next in free list
        freed_iter = nextof(freed_iter);

        // Continue searching chunks in the memory block
        continue;
      }

      // This chunk is not free (allocated), so call its destructor
      static_cast<T *>(static_cast<void *>(i))->~T();
      // and continue searching chunks in the memory block
    }

    // free storage
    UserAllocator::free(iter.begin());

    // increment iter
    iter = next;
  } while (iter.valid());

  // Make the block list empty so that the inherited destructor doesn’t try to
  //  free it again.
  this->list.invalidate();
}

这段代码不难理解,object_pool遍历所有申请的内存块(MemBlock),并遍历其中所有结点(Node),如果该结点不出现在自由内存结点(FreeNode)的列表(FreeNodeList)中,那么,它就是用户未主动释放的结点,需要进行相应的析构操作。

现在你明白了,ordered_malloc是为了让MemBlockList中的MemBlock有序,ordered_free是为了让FreeNodeList中的所有FreeNode有序。而MemBlockList, FreeNodeList有序,是为了更快地检测Node是自由的还是被使用的(这实际上是一个集合求交的流程,建议你看看std::set_intersection,它定义在STL的<algorithm>中)。

时间: 2024-11-03 22:36:31

C++内存管理变革(4): boost::object_pool的相关文章

C++内存管理变革(3):另类内存管理

最简单的C++/Java程序 最简单的Java程序: class Program { public static void main() { new int; } } 对应的C++程序: void main() { new int; } 我想没有一个Java程序员会认为上面的Java代码存在问题.但是所有严谨的C++程序员则马上指出:上面这个C++程序有问题,它存在内存泄漏.但是我今天想和大家交流的一个观念是:这个C++程序没有什么问题. DocX程序的内存管理 DocX是我开发的一个文档撰写工

C++内存管理变革(2):最袖珍的垃圾回收器

概述 C/C++最被人诟病的,可能是没有一个内存垃圾回收器(确切是说没有一个标准的垃圾回收器).本文讨论的内容要点是,在C/C++中实现一个最袖珍的.功能受限的垃圾回收器.这个垃圾回收器区别于其他垃圾回收器的主要特征是: 1. 袖珍但具实用性.整个垃圾回收器代码行数100行左右(不含空白行),相当小巧.相对而言,它的功能也受到一定的限制.但是它在很多关键的场合恰恰非常有用.该垃圾回收器以实用作为首要目标,已经成为我和身边一些同事编程的重要工具. 2. 高性能.区别于其他垃圾回收器的是这个袖珍的垃

C++内存管理变革

引言 C/C++语言的内存管理经历了几次变革,但至今仍未能趋于成熟.这几次变革主要包括: 1. 从malloc/free到new/delete.这场变革是OOP技术兴起的产物.C++是强类型语言,new/delete的主要成果也就是加强了类型观念,减少了强制类型转换的需求.但是从内存管理角度看,这个变革并没有多少的突破性. 2. 从new/delete到内存配置器(allocator).自从STL被纳入C++标准库后,C++世界产生了巨大的变化.而从内存管理角度来看,allocator的引入也是

c++内存管理学习纲要

本系列文章,主要是学习c++内存管理这一块的学习笔记. 时间:6.7-21 之下以技术内幕的开头语,带入到学习C++内存管理的技术中吧: 内存管理是C++最令人切齿痛恨的问题,也是C++最有争议的问题,因此要想成为C++高手,内存管理一关是必须要过的! 笔记汇总: 1.C++内存管理学习笔记(1) 2.C++内存管理学习笔记(2) 3.C++内存管理学习笔记(3) 4.C++内存管理学习笔记(4) 5.C++内存管理学习笔记(5) 6.C++内存管理学习笔记(6) 7.C++内存管理学习笔记(7

c++内存管理学习笔记结束语

         刚开学学习内存管理这一块时,发现需要对一些知识需要做一些笔记,打算向以前学习的方式一样,写在纸上,鉴于以前自己笔记的莫名的丢失,所以就打算发在了博客上.写在博客上有这么几个好处, 一是互联网上的学习资源很丰富,随时可以查找学习:二是利用博客的形式来做笔记能够与其他学习者分享.互相讨论.互相学习(虽然目前评论数不多-.):三是博客内容不容易丢失,除非哪天csdn说不做了,哈哈.        在学习过程中,我读了很对的相关书籍和文献,以及网上其他人的优秀博客.其中那些精辟到位的技

C++内存管理学习笔记(5)

/****************************************************************/ /*            学习是合作和分享式的! /* Author:Atlas                    Email:wdzxl198@163.com  /*  转载请注明本文出处: *   http://blog.csdn.net/wdzxl198/article/details/9112123 /************************

C++内存管理学习笔记(4)

/****************************************************************/ /*            学习是合作和分享式的! /* Author:Atlas                    Email:wdzxl198@163.com    /*  转载请注明本文出处: *   http://blog.csdn.net/wdzxl198/article/details/9094793 /**********************

聊聊内存管理

这篇文章我们聊聊内存管理. 本来我想不针对于任何具体的操作系统来谈内存管理,但是又觉得不接地气.言之无物.所以我决定在阐述概念的同时,还针对IA32平台Linux下的内存管理做简要的介绍,并且以实验来证明结论.以下内容分拆为几个大标题和小节,内容前后承接. 物理地址空间 首先,什么是物理地址空间?我们知道CPU与外部进行信息传递的公用通道就是总线,一般而言,CPU有三大总线:控制总线.数据总线.地址总线.这三类总线在一定程度上决定了CPU对外部设备的控制和数据传送能力.其中地址总线决定了CPU能

c#内存管理.

尽管在.net framework中我们不太需要关注内存管理和垃圾回收这方面的问题,但是出于提高我们应用程序性能的目的,在我们的脑子里还是需要有这方面的意识.明白内存管理的基本行为将有助于我们解释我们程序中变量是如何操作的.在本文中我将讨论栈和堆的一些基本知识,变量的类型和某些变量的工作原理. 当你在执行程序的时候内存中有两个地方用于存储程序变量.如果你还不知道,那么就来看看堆和栈的概念.堆和栈都是用于帮助我们程序运行的,包含某些特殊信息的操作系统内存模块.那么堆和栈有什么不同呢? 堆VS栈的区