什么是池<> ::的malloc和boost ::池<> :: ordere

2019-08-21 16:31发布

我使用boost.pool,但我不知道什么时候使用boost::pool<>::mallocboost::pool<>::ordered_malloc

所以,

  1. 有什么的不同boost::pool<>::mallocboost::pool<>::ordered_malloc

  2. 当我应该使用boost::pool<>::ordered_malloc

Answer 1:

首先,我们应该了解Boost库池背后的基本思想是: simple_segregated_storage ,它类似于一个单向链表,并负责划分内存块成固定大小的块:

一个内存池保留的内存块的空闲列表。 因此,我们提到的块和块:存储池使用newmalloc分配一个内存块,并将其划分成具有相同尺寸的许多内存块。
假定地址由8,4个字节,用于存储下一个块的地址对齐,因此存储器块(8个字节×32点的块)为如下(存储器地址是仅仅用于说明问题,而不是真实的):

现在,假设用户分配8个字节存储器的两倍,因此在块:[0xDD00,0xDD08),[0xDD08,0xDD10)被使用。 一段时间后,用户释放在[0xDD00,0xDD08)的内存,所以这个块将回到空闲列表中。 现在,块是这样的:


然后用户释放在[0xDD08,0xDD10内存),该块放回列表最简单的办法是更新first指向它,常量时间复杂度。 所述simple_segregated_storage<T>::free()被精确地这样做:

void free BOOST_PREVENT_MACRO_SUBSTITUTION(void * const chunk)
{ //! Free a chunk.
  //! \pre chunk was previously returned from a malloc() referring to the same free list.
  //! \post !empty()
   BOOST_POOL_VALIDATE_INTERNALS
  nextof(chunk) = first;
  first = chunk;
  BOOST_POOL_VALIDATE_INTERNALS
}

在此之后,该列表会是这样:

现在,我们注意到块的列表中的地址,这些操作后,不会下令! 如果我们想保留,同时解除分配的顺序,可以调用pool<>::ordered_free()代替pool<>::free()到地方的记忆回到其正确的顺序列表。 现在我们已经知道什么是在内存池的顺序,让我们深入的源代码boost::pool<>::mallocboost::pool<>::ordered_malloc

void * malloc BOOST_PREVENT_MACRO_SUBSTITUTION()
{
  if (!store().empty())
    return (store().malloc)();
  return malloc_need_resize();
}

void * ordered_malloc()
{
  if (!store().empty())
    return (store().malloc)();
  return ordered_malloc_need_resize();
}

正如我们所看到的,它们的区别只有当内存块的列表中没有空闲块。 在这种情况下,它分配一个新的内存块,其合并空闲列表到池的空闲列表中,这两种方法之间的区别在于boost::pool<>::ordered_malloc保持秩序,同时合并空闲列表。
以上是对问题1。
那么,为什么顺序事? 看来内存池与无序块完美的作品!
首先,如果我们想求n块的连续序列,有序空闲列表会更容易。 其次,让我们来看看派生类boost::poolboost::object_pool ,它提供了对破坏非释放对象的自动销毁object_pool对象,而你也可以手动销毁对象,例如:

class X { … };

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

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

上面的代码是OK,没有内存泄漏或双删除! 如何boost::object_pool做到这一点魔法? 让我们找到的析构函数执行boost::object_pool (我有升压1.48我的机器上):

template <typename T, typename UserAllocator>
object_pool<T, UserAllocator>::~object_pool()
{
#ifndef BOOST_POOL_VALGRIND
  // handle trivial case of invalid list.
  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();
#else
   // destruct all used elements:
   for(std::set<void*>::iterator pos = this->used_list.begin(); pos != this->used_list.end(); ++pos)
   {
      static_cast<T*>(*pos)->~T();
   }
   // base class will actually free the memory...
#endif
}

它通过在内存块的列表中的所有数据块( list ,数据成员boost::pool<>拥有系统分配的所有内存块的位置和大小)找到任何块是否还显示,空闲列表,如果没有,调用该对象的析构函数,然后释放内存。 所以这有点让两个集合的交集,就像的std :: set_intersection()呢! 如果列表进行排序,这将是更快做到这一点。 其实在boost::object_pool<>需要秩序,公众成员函数: boost::object_pool<>::malloc()boost::object_pool<>::free()只需要调用boost::pool<>::ordered_malloc()boost::pool<>::ordered_free()分别为:

element_type * malloc BOOST_PREVENT_MACRO_SUBSTITUTION()
{ //! Allocates memory that can hold one object of type ElementType.
  //!
  //! If out of memory, returns 0. 
  //!
  //! Amortized O(1).
  return static_cast<element_type *>(store().ordered_malloc());
}
void free BOOST_PREVENT_MACRO_SUBSTITUTION(element_type * const chunk)
{ //! De-Allocates memory that holds a chunk of type ElementType.
  //!
  //!  Note that p may not be 0.\n
  //!
  //! Note that the destructor for p is not called. O(N).
  store().ordered_free(chunk);
}

所以对于queston 2:你不必使用boost::pool<>::ordered_malloc在大多数情况下。



文章来源: what's the difference between boost::pool<>::malloc and boost::pool<>::ordered_malloc, and when should I use boost::pool<>::ordered_malloc?
标签: boost pool