Boost Pool最大尺寸

时间:2013-05-27 10:51:30

标签: c++ boost boost-pool

我使用boost池作为静态内存提供程序,

void func()
{
  std::vector<int, boost::pool_allocator<int> > v;
  for (int i = 0; i < 10000; ++i)
    v.push_back(13);
}

在上面的代码中,我们如何修复池的大小,我的意思是我们知道boost :: pool提供静态内存分配器,但我无法修复此池的大小,它继续增长,那里应该是限制其规模的方法。 例如,我只想要一个200块的池,所以我可以采取200块,之后它应该是NULL 请让我现在该怎么做

1 个答案:

答案 0 :(得分:4)

我不认为助推池提供你想要的东西。实际上,boost::pool_allocator还有4个其他模板参数,除了对象的类型:

  • UserAllocator:定义基础池用于从系统分配内存的方法(默认= boost::default_user_allocator_new_delete)。
  • Mutex:允许用户确定要在底层singleton_pool上使用的同步类型(默认= boost::details::pool::default_mutex)。
  • NextSize:此参数的值在创建时传递给基础池,并指定在第一个分配请求中分配的块数(默认值= 32)。
  • MaxSize:此参数的值在创建时传递给基础池,并指定在任何单个分配请求中分配的最大块数(默认值= 0)。

您可能认为MaxSize正是您想要的,但不幸的是,它不是。 boost::pool_allocator使用基于boost::singleton_pool的基础boost::poolMaxSize最终将传递给boost::pool<>max_size的数据成员,那么max_sizeboost::pool中扮演什么角色?我们来看看boost::pool::malloc()

void * malloc BOOST_PREVENT_MACRO_SUBSTITUTION()
{ //! Allocates a chunk of memory. Searches in the list of memory blocks
  //! for a block that has a free chunk, and returns that free chunk if found.
  //! Otherwise, creates a new memory block, adds its free list to pool's free list,
  //! \returns a free chunk from that block.
  //! If a new memory block cannot be allocated, returns 0. Amortized O(1).
  // Look for a non-empty storage
  if (!store().empty())
    return (store().malloc)();
  return malloc_need_resize();
}

显然,如果内存块中没有可用的空闲块, boost::pool会立即分配一个新的内存块。让我们继续深入研究malloc_need_resize()

template <typename UserAllocator>
void * pool<UserAllocator>::malloc_need_resize()
{ //! No memory in any of our storages; make a new storage,
  //!  Allocates chunk in newly malloc aftert resize.
  //! \returns pointer to chunk.
  size_type partition_size = alloc_size();
  size_type POD_size = static_cast<size_type>(next_size * partition_size +
      math::static_lcm<sizeof(size_type), sizeof(void *)>::value + sizeof(size_type));
  char * ptr = (UserAllocator::malloc)(POD_size);
  if (ptr == 0)
  {
     if(next_size > 4)
     {
        next_size >>= 1;
        partition_size = alloc_size();
        POD_size = static_cast<size_type>(next_size * partition_size +
            math::static_lcm<sizeof(size_type), sizeof(void *)>::value + sizeof(size_type));
        ptr = (UserAllocator::malloc)(POD_size);
     }
     if(ptr == 0)
        return 0;
  }
  const details::PODptr<size_type> node(ptr, POD_size);

  BOOST_USING_STD_MIN();
  if(!max_size)
    next_size <<= 1;
  else if( next_size*partition_size/requested_size < max_size)
    next_size = min BOOST_PREVENT_MACRO_SUBSTITUTION(next_size << 1, max_size*requested_size/ partition_size);

  //  initialize it,
  store().add_block(node.begin(), node.element_size(), partition_size);

  //  insert it into the list,
  node.next(list);
  list = node;

  //  and return a chunk from it.
  return (store().malloc)();
}

正如我们从源代码中看到的那样, max_size只与下次从系统请求的块数相关,我们只能减慢增加速度这个参数。
但请注意,我们可以定义底层池用于从系统分配内存的方法,如果我们限制从系统分配的内存大小,则池的大小不会继续增长。在此方式,boost::pool似乎是多余的,您可以直接将自定义分配器传递给STL容器。以下是自定义分配器(基于此link)的示例,它从堆栈中分配内存到给定大小:

#include <cassert>
#include <iostream>
#include <vector>
#include <new>

template <std::size_t N>
class arena
{
    static const std::size_t alignment = 8;
    alignas(alignment) char buf_[N];
    char* ptr_;

    bool
        pointer_in_buffer(char* p) noexcept
    { return buf_ <= p && p <= buf_ + N; }

public:
    arena() noexcept : ptr_(buf_) {}
    ~arena() { ptr_ = nullptr; }
    arena(const arena&) = delete;
    arena& operator=(const arena&) = delete;

    char* allocate(std::size_t n);
    void deallocate(char* p, std::size_t n) noexcept;

    static constexpr std::size_t size() { return N; }
    std::size_t used() const { return static_cast<std::size_t>(ptr_ - buf_); }
    void reset() { ptr_ = buf_; }
};

template <std::size_t N>
char*
arena<N>::allocate(std::size_t n)
{
    assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena");
    if (buf_ + N - ptr_ >= n)
    {
        char* r = ptr_;
        ptr_ += n;
        return r;
    }
    std::cout << "no memory available!\n";
    return NULL;
}

template <std::size_t N>
void
arena<N>::deallocate(char* p, std::size_t n) noexcept
{
    assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena");
    if (pointer_in_buffer(p))
    {
        if (p + n == ptr_)
            ptr_ = p;
    }
}

template <class T, std::size_t N>
class short_alloc
{
    arena<N>& a_;
public:
    typedef T value_type;

public:
    template <class _Up> struct rebind { typedef short_alloc<_Up, N> other; };

    short_alloc(arena<N>& a) noexcept : a_(a) {}
    template <class U>
    short_alloc(const short_alloc<U, N>& a) noexcept
        : a_(a.a_) {}
    short_alloc(const short_alloc&) = default;
    short_alloc& operator=(const short_alloc&) = delete;

    T* allocate(std::size_t n)
    {
        return reinterpret_cast<T*>(a_.allocate(n*sizeof(T)));
    }
    void deallocate(T* p, std::size_t n) noexcept
    {
        a_.deallocate(reinterpret_cast<char*>(p), n*sizeof(T));
    }

    template <class T1, std::size_t N1, class U, std::size_t M>
    friend
        bool
        operator==(const short_alloc<T1, N1>& x, const short_alloc<U, M>& y) noexcept;

    template <class U, std::size_t M> friend class short_alloc;
};

template <class T, std::size_t N, class U, std::size_t M>
inline
bool
operator==(const short_alloc<T, N>& x, const short_alloc<U, M>& y) noexcept
{
    return N == M && &x.a_ == &y.a_;
}

template <class T, std::size_t N, class U, std::size_t M>
inline
bool
operator!=(const short_alloc<T, N>& x, const short_alloc<U, M>& y) noexcept
{
    return !(x == y);
}


int main()
{
    const unsigned N = 1024;
    typedef short_alloc<int, N> Alloc;
    typedef std::vector<int, Alloc> SmallVector;
    arena<N> a;
    SmallVector v{ Alloc(a) };
    for (int i = 0; i < 400; ++i)
    {
        v.push_back(10);
    }

}