Максимальный размер пула Boost

Я использую boost-пул в качестве поставщика статической памяти,

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

В вышеприведенном коде, как мы можем исправить размер пула, я имею в виду, поскольку мы знаем, что boost:: pool предоставляет как распределитель статической памяти, но я не могу исправить размер этого пула, его продолжать расти, там должен быть способ ограничить его размер. например, я хочу пул из 200 кусков, так что я могу взять 200 кусков, после чего он должен, хотя NULL пожалуйста, позвольте мне теперь, как это сделать

1 ответ

Я не думаю, что форсированный пул обеспечивает то, что вы хотите. На самом деле есть 4 других параметра шаблона для boost::pool_allocator кроме типа объекта:

  • 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::pool, MaxSize в конечном итоге перейдет к элементу данных boost::pool<>: max_size, и какую роль играет max_size в boost::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 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)();
}
</size_type></sizeof(size_type),></size_type></sizeof(size_type),></size_type></userallocator></typename>

Как видно из исходного кода, max_size просто связано с количеством блоков для запроса из системы в следующий раз, мы можем только замедлить скорость увеличения с помощью этого параметра. Но обратите внимание, что мы можем определить метод, который базовый пул будет использовать для выделения памяти из системы, если мы ограничим размер памяти, выделенной из системы, размер пула не будет расти. В этом путь, boost::pool представляется излишним, вы можете напрямую передать пользовательский распределитель в контейнер STL. Вот пример пользовательского распределителя (на основе этой ссылка), которая выделяет память из стека до заданного размера:

#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,="" u,="" 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,="" u,="" 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,="" u,="" 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);
 }
}
</n></int,></int,></u,></t,></class></u,></t,></class></class></u,></t1,></class></char*></t*></u,></class></n></class></n></class></n></std::size_t></n></std::size_t></std::size_t></std::size_t></new></vector></iostream></cassert>

licensed under cc by-sa 3.0 with attribution.