-
boost pool_allocator 분석프로그래밍/c++ 2016. 1. 14. 23:30반응형
부스트 풀 메모리 할당자
헤더
#include <boost/pool/pool_alloc.hpp>
특징
스레드에 안전함
rebind 지원
가변 크기 지원
pool_allocator
vector와 같은 연속적인 메모리를 가지는 자료형 할당에 적합한 할당자. 내부적으로 singleton_pool을 사용하고, singleton_pool은 pool을 전역적으로 사용할 수 있도록 만든 클래스
pool_allocator::allocate 호출 시 다음과 같은 호출 과정을 거침
pool::ordered_malloc 내부
123456789101112131415template <typename UserAllocator>void * pool<UserAllocator>::ordered_malloc(const size_type n){ //! Gets address of a chunk n, allocating new memory if not already available.//! \returns Address of chunk n if allocated ok.//! \returns 0 if not enough memory for n chunks.const size_type partition_size = alloc_size();const size_type total_req_size = n * requested_size;const size_type num_chunks = total_req_size / partition_size +((total_req_size % partition_size) ? true : false);void * ret = store().malloc_n(num_chunks, partition_size); // sss에서 메모리를 할당을 시도.//… 이 아래는 ret이 0(0 or nullptr)일 때 처리하는 루틴}cs simple segregated storage의 malloc_n
\1234567891011121314151617181920212223template <typename SizeType>void * simple_segregated_storage<SizeType>::malloc_n(const size_type n,const size_type partition_size){BOOST_POOL_VALIDATE_INTERNALSif(n == 0)return 0;void * start = &first; // 메모리 검색을 시작할 위치 설정(sss 노드의 첫번째)void * iter;do{if (nextof(start) == 0) // start의 다음 노드가 없다면(nextof(start) == nullptr) 0 반환return 0;// start에서 할당을 시도함iter = try_malloc_n(start, n, partition_size);// try_malloc_n을 빠져나오면 start는 다음으로 검사할 노드가 된다.} while (iter == 0); // iter가 0이면 계속void * const ret = nextof(start);nextof(start) = nextof(iter);BOOST_POOL_VALIDATE_INTERNALSreturn ret;}cs simple segregated storage의 try_malloc_nsada1234567891011121314151617181920212223242526272829template <typename SizeType>void * simple_segregated_storage<SizeType>::try_malloc_n(void * & start, size_type n, const size_type partition_size){// iter = 검색할 시작 노드의 다음 노드void * iter = nextof(start);// @begin// partition_size * n만큼 연속적인지 검사합니다.//while (--n != 0){void * next = nextof(iter);// 필요한 만큼(n*partition_size) 연속적인지 검사// next == (char*)iter + partition_size라면 다음 청크가 이어져있다는 것if (next != static_cast<char *>(iter) + partition_size){// next가 없거나(nullptr, end of list) partition_size만큼 연속적이지 않다면// start를 다음에 검사할 지점으로 설정하고 반환start = iter;return 0;}iter = next;}// @end// 위 테스트를 통과했다면 값을 담아서 반환return iter;}cs 인상 깊었던 부분은 next != static_cast<char*>(iter) + partition_size
내가 예전에 메모리 풀을 만들었을 땐 청크 노드의 앞 부분에 size를 써놨었는데, boost pool_allocator는 위의 저 연산을 통해 연속적인 메모리 여부를 검사한다.
다음 메모리 청크가 현재 메모리청크 + 파티션사이즈(바이트 단위로 이동한 주소!) 이면 직렬화된 메모리
결론은 이런 구조의 메모리 리스트에서 적합한 메모리를 찾는다는 것
적합한 메모리가 없으면 새롭게 할당한다. 여튼 메모리 할당 방식을 버디 메모리 할당이라고 함.
pool에서 할당한 메모리를 해제할 때에도 저 메모리 리스트에서 삽입할 적절한 위치를 찾는 과정이 있는데,
12345678910111213141516171819// Same preconditions as 'segregate'// Post: !empty()void add_ordered_block(void * const block,const size_type nsz, const size_type npartition_sz){ //! add block (ordered into list)//! This (slower) version of add_block segregates the//! block and merges its free list into our free list//! in the proper order.BOOST_POOL_VALIDATE_INTERNALS// Find where "block" would go in the free listvoid * const loc = find_prev(block); // 해제할 메모리 블럭의 이전 위치를 찾음// Place either at beginning or in middle/endif (loc == 0)add_block(block, nsz, npartition_sz);elsenextof(loc) = segregate(block, nsz, npartition_sz, nextof(loc));BOOST_POOL_VALIDATE_INTERNALS}cs 이는 위 코드에서 11번 라인에서 확인할 수 있다.
boost의 pool은 다른 메모리 풀 라이브러리와는 다르게 가변 크기를 지원한다길래 어떤식으로 되어있을까 찾아봤다.
free list에서 연속적인 메모리가 없으면 새로 할당, 있으면 재사용.
-끝-
반응형'프로그래밍 > c++' 카테고리의 다른 글
boost::property_tree를 이용해 xml 데이터 파싱하기 (0) 2016.01.22 boost::lockfree::spsc_queue 사용 시 주의할 점 (0) 2016.01.18 boost::lockfree::queue의 타입 제한(error C2338) (0) 2016.01.13 shared_mutex, 그리고 upgrade_lock. (0) 2015.12.28 vs2015 update1에서 c++17 module 기능 사용하기 (0) 2015.12.16