自定义内存堆上的boost :: object_pool

时间:2013-11-07 06:26:40

标签: c++ boost object-pooling

我想创建一个对象池,但我希望它只在我的内存堆的特定段上分配内存。有没有办法使用boost?

1 个答案:

答案 0 :(得分:3)

Boost.Pool的object_pool允许用户通过提供UserAllocator来控制池使用的内存。根据文件:

  

池对象需要从系统请求内存块,然后池将其拆分为块以分配给用户。通过为各种Pool接口指定UserAllocator模板参数,用户可以控制如何分配这些系统内存块。

Boost.Pool仅提供使用new/deletemalloc/free的基本分配器。但是,如果可以编写分配器以在免费存储的特定段中进行分配,则object_pool也可以配置为执行此操作。可能有必要检查编译器和平台是否支持将免费存储中的分配限制为特定段。


这是一个基本示例,我忽略了一些细节以保持示例简单,并显示类型如何满足UserAllocator的要求。在此示例中,boost::object_pool将使用使用预分配静态内存的自定义分配器。

#include <iostream>
#include <boost/array.hpp>
#include <boost/pool/object_pool.hpp>

namespace detail {

/// @brief Pre-allocated managed memory block.
template <std::size_t N>
class arena
{
public:

  /// @brief Constructor.
  arena()
    : current_(&buffer_.front()), // Set current to start.
      end_(current_ + N)          // End sentinel.
  {
    std::cout << "arena memory range: "
              << static_cast<void*>(current_) << " - "
              << static_cast<const void*>(end_) << std::endl;
  }

  /// @brief Attempt to allocate memory from pre-allocated block.
  /// 
  /// @param n Count of bytes to allocate.
  ///
  /// @param Non-zero if allocation is succesfull.  Otherwise, zero. 
  char* allocate(std::size_t n)
  {
    // If there is no more memory, then return zero.
    if ((current_ + n) > end_) return 0;

    // Otherwise, return available memory and shift current.
    std::cout << "arena allocating: " 
              << static_cast<void*>(current_) << std::endl;
    char* ptr = current_;
    current_ += n;
    return ptr;
  }

  void deallocate(char* p, std::size_t n)
  {
    // ...
  }

private:

  /// @brief Block of memory used for allocations.
  boost::array<char, N> buffer_;

  /// @brief Pointer to current allocation.
  char* current_;

  //// @brief End pointer sentinel.
  const char* end_;
};

} // namespace detail

/// @brief Allocator that meets Boost.Pool's UserAllocator Concepts.
///        This allocator will allocate memory from a pre-allocated
///        block of static memory.  Each instance of the template is
///        considered to be its own unique allocator, and thus has its
///        own memory.  
template <std::size_t N>
class static_allocator
{
public:
  typedef std::size_t size_type;
  typedef std::ptrdiff_t difference_type;

  static char* malloc(const size_type n) { return arena_.allocate(n); }
  static void free(char* p)              { arena_.deallocate(p, 1);   }

private:
  static detail::arena<N> arena_;
};

template <std::size_t N>
detail::arena<N> static_allocator<N>::arena_;

/// @brief Helper type.
template <typename T, std::size_t N>
struct static_object_pool:
  boost::object_pool<T, static_allocator<N * sizeof(T)> >
{};

/// Mockup object.
class Foo {};

int main()
{
  static_object_pool<Foo, 128> pool;

  Foo* a = pool.malloc();
  std::cout << "a is at " << a << std::endl;
  Foo* b = pool.malloc();
  std::cout << "b is at " << b << " -- freeing b" << std::endl;
  pool.free(b);
  Foo* c = pool.malloc();
  std::cout << "c is at " << c << std::endl;
}

输出:

arena memory range: 0x804b5a0 - 0x804b620
arena allocating: 0x804b5a0
a is at 0x804b5a0
b is at 0x804b5a4 -- freeing b
c is at 0x804b5a4

请注意,从object_pool::malloc()返回的每个地址都在竞技场的内存范围内。此外,当b通过pool.free(b)释放时,内存(0x804b5a4)会在malloc() c的下一个{{1}}时立即被池重用。