부스트 풀이 원하는 것을 제공한다고 생각하지 않습니다.
UserAllocator
: 기본 풀 시스템 (기본값 = boost::default_user_allocator_new_delete
)에서 메모리를 할당하는 데 사용할 방법을 정의 실제로 개체의 유형을 제외하고 boost::pool_allocator
4 개 다른 템플릿 매개 변수가 있습니다.
Mutex
: 기본 singleton_pool (기본 = boost::details::pool::default_mutex
)에서 사용할 동기화 유형을 사용자가 결정할 수 있습니다.
NextSize
:이 매개 변수의 값은 기본 풀이 생성 될 때 기본 풀로 전달되고 첫 번째 할당 요청에 할당 할 청크 수를 지정합니다 (기본값 = 32).
MaxSize
:이 매개 변수의 값은 기본 풀이 생성 될 때 기본 풀로 전달되며 단일 할당 요청에서 할당 할 최대 청크 수를 지정합니다 (기본값 = 0).
MaxSize
은 정확히 원하는 것일 수도 있지만 불행히도 그렇지는 않습니다. boost::pool_allocator
는이 boost::pool
을 기반으로 boost::singleton_pool
의 기초는 MaxSize
결국 boost::pool<>
의 데이터 멤버에 전달합니다 사용 max_size
, 그래서 어떤 역할은 boost::pool
의 max_size
놀이를 하는가? 이제 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()
에 파고 계속하자 : 우리는 소스 코드에서 볼 수 있듯이 max_size
가 바로 시스템 다음에서 요청하는 덩어리의 수와 관련되어,
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)();
}
, 우리는 속도를 늦출 수 있습니다 이 매개 변수를 통해 증가하는 것.
그러나 기본 풀이 시스템에서 메모리를 할당하는 데 사용할 방법을 정의 할 수 있습니다. 시스템에서 할당 된 메모리 크기를 제한하면 풀 크기가 계속 커지지 않습니다. 이렇게하면 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);
}
}