The six components of the STL--Allocator (memory allocation, what's so esoteric)

Source: Internet
Author: User
Tags traits types of functions

SGI designed a two-tier Configurator, the first-level configurator directly uses malloc () and free (), and the second-level Configurator uses different strategies depending on the situation: when the configuration chunk exceeds 128bytes, the first-level configurator is called when it is "large enough", and when the configuration area is less than 128bytes, As "too small", in order to reduce the additional burden, the use of complex memory pool collation, and no longer recourse to the first level configurator. The entire design only opens the first Level configurator, depending on whether the _use_malloc is defined:

1 #ifdef __use_malloc2 ...  3typedef __malloc_alloc_template<0>Malloc_alloc; 4typedef Malloc_alloc ALLOC;//make Alloc the first level configurator5 #else  6 //Make Alloc a second-level configurator7typedef __default_alloc_template<__node_allocator_threads,0>Alloc; 8 #endif/*! __use_malloc*/

SGI STL First Level configurator

Template<int inst>

Class __malloc_alloc_template {...};

Comments:

1.allocate () directly using malloc (), deallocate () directly using free ().

2. Simulate C + + Set_new_handler () to handle low memory conditions. The first level Configurator performs the actual memory configuration, deallocation, and reconfiguration operations with C functions such as malloc (), free (), realloc ().

SGI STL Second Level configurator

Template<bool Threads,int inst>

Class __default_alloc_template {...};

Comments:

1. Maintain 16 free lists, responsible for the sub-configuration capability of 16 small blocks. Memory pool is configured with malloc (). If there is not enough memory, go to call the first level configurator.

2. If the demand chunk is greater than 128byte, call the first level configurator.

Here are some specific understandings to share:

Default Allocator

SGI STL's header file defalloc.h has a standard memory allocator called allocator, which simply adds: operator new and:: operator delete is a thin layer of encapsulation. The memory allocator is never used in the containers and algorithms section of the SGI STL.

STL the memory allocation policy

First, a brief introduction to the planning of memory allocation in STL

When the user constructs an object with new, it actually contains two actions: 1) Call: operator new application memory; 2) Call the object's constructor to construct the contents of this object

When the user destroys an object with a delete, there are two actions: 1) The destructor of the object is called to reconstruct the object's contents; 2) Call:: operator delete to free memory

The construction and destruction of objects in SGI STL consists of: construct () and::d Estroy (), memory applications and releases are the responsibility of Alloc:allocate () and Alloc:deallocate (); In addition, SGI STL provides some global functions , which is used to manipulate large chunks of memory data.

The three major modules mentioned in the previous paragraph were stl_construct.h, stl_alloc.h, stl_uninitialized.h , respectively, responsible for

Object construction and destruction tools (Stl_construct.h)

The construction of two objects is provided in Stl_construct.h, with default constructs and assignment constructs:

1Template <class_T1,class_t2>2Inlinevoid_construct (_t1* __p,Const_t2&__value) {3   New((void*) __p) _t1 (__value);4 }5 6Template <class_t1>7Inlinevoid_construct (_t1*__p) {8   New((void*) __p) _t1 ();9}

The function of the above two functions is to construct an object of type T1, and is returned by the pointer p as a parameter.

One of the new (_p) _t1 (_value); The placement new operator is used to construct a _t1 object at the memory address _p by means of a copy. (Placement new enables the construction of an object with the specified type of constructor on the specified memory address).

In terms of object destruction, Stl_construct.h also provides two methods of destructor:

 1  template <class  _tp>2  inline void  _destroy (_tp* __pointer) {  3  __pointer->~_TP ();  4   5  6  template <class  _ Forwarditerator>7  inline void   _destroy (_forwarditerator __first, _forwarditerator __last) { 8   __destroy (__first, __last, __value_type (__first));  9 } 

The first version of the destructor takes a pointer to the object that the pointer refers to, and the second version of the destructor takes first and last two iterators, and the objects within the scope of the two iterators are deconstructed.

In the second version of the Destroy function, using the usual traits techniques in STL, traits will get some characteristics of the current object, and then according to the different characteristics of the different objects to call the corresponding method. In Destroy in Stl_construct.h, the STL parses the type of the Has_trivial_destructor attribute of the object that the iterator refers to (only two: True_type and False_type), and if it is True_type, The STL does nothing, and if it is false_type, the destructor of each object is called to destroy the set of objects.

In addition, STL_CONSTRUCT provides a special version of the Destroy function for some basic types of objects, namely char, int, float, double, long. When the destroy parameters are these basic types, destroy does nothing.

Memory Space management Tool Alloc

I want to introduce the STL allocator in the bottom-down order. First of all, the STL built two kinds of allocator, and then the STL how to encapsulate the two distributors to provide a unified interface, and finally use a vector example to see how the container uses this allocator.

1 __malloc_alloc_template Memory Allocator

The allocator is a package for malloc, ReAlloc, and free:

1 Static void*allocate (size_t __n)2   {3     void* __result =malloc (__n);4     if(0= = __result) __result =_s_oom_malloc (__n);5     return__result;6   }7 8   Static voidDEALLOCATE (void* __p, size_t/*__n*/)9   {Ten Free (__p); One   } A  -   Static void* Reallocate (void* __p, size_t/*OLD_SZ*/, size_t __NEW_SZ) -   { the     void* __result =realloc (__p, __NEW_SZ); -     if(0= = __result) __result =_s_oom_realloc (__p, __NEW_SZ); -     return__result; -}

When the call to malloc and REALLOC requests for less than the memory space, Oom_malloc () and Oom_realloc () are called, and the two functions repeatedly invoke the out of memory handler processing function passed by the user. Until the memory can be requested with malloc or realloc. If the user does not pass __malloc_alloc_oom_handler,__malloc_alloc_template the __throw_bad_alloc exception is thrown. So, the out-of-memory processing task is given to the class client to complete.

2 __default_alloc_template Dispenser

This allocator uses the idea of a memory pool, effectively avoiding the problem of internal fragments (in a word, the fragment and outer fragments are described in the way: the fragments are allocated but not used in the memory space, the outer fragments are too small to be allocated out of the free block). If the requested memory block is greater than 128bytes, the requested operation is transferred to the __malloc_alloc_template allocator for processing, and if the requested chunk size is less than 128bytes, the memory allocated from the memory pool maintained by this allocator. The allocator maintains free space in the memory pool with an idle list, and the idle list is probably similar to the following shape:

As shown, S_free_list is an array of starting addresses for these free partition chains, with a size of 16. The size of the free space in each of the 16 linked lists is fixed, and the free block size of the first list is 8bytes, followed by a total of four, four, four, three, four, four, five, five, five, ten, five, 104, and 128bytes.

There are also three pointers s_start_free, S_end_free, S_heap_size. They point to the start address, end address, and free space size of the entire memory pool, respectively.

To allocate memory procedures:

1) If the requested memory space is greater than 128bytes, the first allocator is processed

2) The allocator first increases the size of the requested memory to a multiple of 8 N, and finds its corresponding idle list address according to N __my_free_list

3) If there are free blocks available in the free list, return the free block and update the __my_free_list, otherwise go to 4)

4) To this step, it means that no free blocks are available in __my_free_list, and the allocator will handle the following steps:

A) try calling _s_chunk_alloc () to request the size of the n*20 memory space, note that at this time may not be able to apply to the n*20 size of memory space

b) If only the memory space of size n is applied, it is returned to the user, otherwise to c)

c) will apply to the n*x (a in said, not necessarily n*20) memory block out of a return to the user, the rest of the memory block chain to the idle list __my_free_list

The specific process for _s_chunk_alloc () is:

1) If the space between _s_start_free and _s_end_free is sufficient to allocate n*20-sized memory space, remove the n*20-sized memory space from this space, update the _s_start_free and return the start address of the requested memory space, or go to 2)

2) If space between _s_start_free and _s_end_free is sufficient to allocate more than N of memory space, allocate an integer times N of memory space, update _s_start_free, return this integer by Nobj, and return the start address of the requested memory space ; otherwise go to 3)

3) To this step, the memory pool is not even a block of memory size n, if there is some memory in the memory pool (these memory size is certainly less than N), then the memory is inserted into its corresponding size of the free partition chain

4) Call malloc to request a memory space of size (2*n*20 + additional) for the run-time library, update _s_start_free, _s_end_free and _s_heap_size, and recall _s_chunk_alloc () if the request succeeds, Otherwise go to 5)

5) To this step, explain 4) in the call to malloc failure, when the allocator loops through 16 free partition chain, as long as there is a free chain, the chain to release a node, re-call _s_chunk_alloc ()

Memory Release Process:

The memory release process is simple, it accepts two parameters, one is the pointer to the memory block to be freed P, and the other represents the size n of the memory block to be freed. The allocator first determines that n, if n>128bytes, is disposed of by the first allocator, otherwise the memory block is added to the corresponding idle list.

SGI STL, for user-friendly access, wraps an interface (an externally supplied allocator interface) for the two above-mentioned allocators, which is as follows:

1template<class_TP,class_alloc>2 classSimple_alloc {3 4  Public:5     Static_tp*allocate (size_t __n)6{return 0= = __n?0: (_tp*) _alloc::allocate (__n *sizeof(_TP)); }7     Static_tp* Allocate (void)8{return(_tp*) _alloc::allocate (sizeof(_TP)); }9     Static voidDeallocate (_tp*__p, size_t __n)Ten{if(0! = __n) _alloc::d eallocate (__p, __n *sizeof(_TP)); } One     Static voidDeallocate (_tp*__p) A{_alloc::d eallocate (__p,sizeof(_TP)); } -};

When the user invokes the allocator, it passes the allocator to be used for the second template parameter of Simple_alloc.

Vector (user mode) using the code of the STL allocator, you can see that the base class of the vector calls Simple_alloc as its allocator:

1Template <class_TP,class_alloc>2     //Cobbliu Note: The base class for STL vectors3 class_vector_base {4  Public:5 typedef _alloc Allocator_type;6Allocator_type Get_allocator ()Const{returnAllocator_type ();}7 8_vector_base (Const_alloc&)9: _m_start (0), _m_finish (0), _m_end_of_storage (0) {}Ten_vector_base (size_t __n,Const_alloc&) One: _m_start (0), _m_finish (0), _m_end_of_storage (0)  A   { -_m_start =_m_allocate (__n); -_m_finish =_m_start; the_m_end_of_storage = _m_start +__n; -   } -  -~_vector_base () {_m_deallocate (_m_start, _m_end_of_storage-_m_start); } +  - protected: +_tp*_m_start; A_tp*_m_finish; at_tp*_m_end_of_storage; -  -typedef SIMPLE_ALLOC&LT;_TP, _alloc>_m_data_allocator; -_tp*_m_allocate (size_t __n) -{return_m_data_allocator::allocate (__n);} -   void_m_deallocate (_tp*__p, size_t __n) in {_m_data_allocator::d eallocate (__p, __n);} -};

Basic Memory processing Tools

In addition to the above memory allocator, STL provides three types of memory processing tools: Uninitialized_copy (), Uninitialized_fill (), and Uninitialized_fill_n (). The implementation code for these three types of functions is in the header file stl_uninitialized.h.

The uninitialized_copy () looks like this:

 1  template <class  _inputiter, Span style= "color: #0000ff;" >class  _forwarditer>2  inline _ Forwarditer  3   Uninitialized_copy (_                     Inputiter __first, _inputiter __last,  4   _forwarditer __result)  5  { 
   
    6  
    return  
     __uninitialized_copy (__first                              , __last, __result,  
    7  
     __value_type (__result));  
    8 } 
   

Uninitialized_copy () copies the objects between the iterators _first and _last to where the iterator _result began. It calls the __uninitialized_copy (__first, __last, __result,__value_type (__result)) to determine the iterator _ Whether the object referred to by result is the pod type (the pod type is the class that owns the constructor, Deconstructor, copy, assignment functions), and if it is a pod type, the copy implementation of the algorithm library is called; otherwise traversal iterator _ The element between the first~_last and the new element is constructed at the _result start address at one by one.

The Uninitialized_fill () looks like this:

 1  template <class  _forwarditer, class  _tp>void   Uninitialized_fill (_forwarditer __first,  3   _forwarditer __last, /span>4   __x)  5  {  __ Uninitialized_fill (__first, __last, __x, __value_type (__first));  7 } 

Uninitialized_fill () Initializes all elements in the iterator _first and _last ranges to X. It calls the __uninitialized_fill (__first, __last, __x, __value_type (__first)) to determine whether the object referred to by the iterator _first is of the pod type, and if it is a pod type, The fill implementation of the algorithm library is called; otherwise one by one constructs.

Uninitialized_fill_n () looks like this:

1 template <class class _tp>23const _tp& __x)4{5    return  __uninitialized_fill_n (__first, __n, __x, __value_type (__first)); 6 }

Uninitialized_fill_n () initializes the n elements at the beginning of the iterator _first to X. It calls the __uninitialized_fill_n (__first, __n, __x, __value_type (__first)) to determine if the iterator _first the object is the pod type, and if so, calls the Fill_n implementation of the algorithm library ; otherwise one by one constructs.

The six components of the STL--Allocator (memory allocation, what's so esoteric)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.