2013-05-27 5 views
4

, 위의 코드에서부스트 풀의 최대 크기를 우리가 풀의 크기를 해결할 수있는 방법을 내가 정적 메모리 공급자로 부스트 풀을 사용하고

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

, 내 말 :: 풀이로 제공 정적 메모리 할당 자,하지만 난이 수영장의 크기를 해결할 수 없습니다, 계속 성장, 크기를 제한하는 방법이 있어야합니다. 예를 들어, 나는 단지 200 개의 청크 풀을 원하기 때문에 나중에 200 개의 청크를 가져갈 수 있습니다. 지금이 방법을 알려주세요.

답변

4

부스트 풀이 원하는 것을 제공한다고 생각하지 않습니다.

  • 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::poolmax_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); 
    } 

}