boost :: pool <> :: malloc和boost :: pool <> :: ordered_malloc之间有什么区别,什么时候应该使用boost :: pool <> :: ordered_malloc?

我使用boost.pool,但是我不知道什么时候使用boost :: pool<> :: malloc和boost :: pool<> :: ordered_malloc?

所以,

> boost :: pool> :: malloc和boost :: pool<> :: ordered_malloc有什么区别?
>何时应该使用boost :: pool<> :: ordered_malloc?

谢谢!

首先,我们应该知道Boost Pool库的基本思路:simple_segregated_storage,它类似于单链表,并且负责将内存块分割成固定大小的块:
  

内存池保留了一个空闲的内存块列表.所以我们提到了块和块:内存池使用new或malloc来分配一个内存块,并将它分成许多具有相同大小的内存块.
假设地址对齐8,4字节,用于存储下一个块的地址,因此存储块(8个字节* 32个块)如下所示(内存地址仅用于说明问题,而不是真实的):

现在,假设用户分配8个字节的内存两次,所以使用块:[0xDD00,0xDD08],[0xDD08,0xDD10].过了一会儿,用户在[0xDD00,0xDD08]释放内存,所以这个块将返回到空闲列表.现在块是这样的:

之后,用户以[0xDD08,0xDD10]的方式释放内存,把这个块放回列表中的最简单的方法就是先把它更新到指向它的常数时间复杂度. 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 :: malloc和boost :: 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 :: pool:boost :: 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
}

它遍历存储器块列表中的所有块(列表,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);
}

所以对于任务2:在大多数情况下,您不需要使用boost :: pool<> :: ordered_malloc.

翻译自:https://stackoverflow.com/questions/15942012/whats-the-difference-between-boostpoolmalloc-and-boostpoolordered-m

转载注明原文:boost :: pool <> :: malloc和boost :: pool <> :: ordered_malloc之间有什么区别,什么时候应该使用boost :: pool <> :: ordered_malloc?