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

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

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
пожалуйста, дайте мне сейчас, как это сделать

5

Решение

Я не думаю, что Boost Pool обеспечивает то, что вы хотите. На самом деле есть 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'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. Вот пример пользовательского распределителя (на основе этого ссылка на сайт) который выделяет память из стека до заданного размера:

#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);
}

}
4

Другие решения

Других решений пока нет …