Space configurator in stl and stl space Configurator
The common c ++ memory configuration is as follows:
class Foo { ... };Foo* pf = new Foo; delete pf;
The new here is actually executed in two parts. First, configure the memory with: operator new, and then execute Foo: Foo () to construct the object content. The same is true for delete. Run Foo: ~ first ::~ Foo () destructor, And then: operator delete to release the memory. In sgi stl, the two parts are in <stl_alloc.h> and <stl_construct.h> respectively. This article describes the story in <stl_alloc.h>.
In sgi stl, The Configurator is divided into two levels. The first level directly uses malloc and free to manage the memory, and the second level uses the memory pool to avoid memory fragmentation. Both levels are packaged by simple_alloc to comply with stl standards.
The first level does not use operator new, so you need to implement the new-handler mechanism by yourself. The counterfeit code is as follows:
1 # ifndef _ MALLOC_ALLOC_H _ 2 # define _ MALLOC_ALLOC_H _ 3 4 // The exception thrown when the definition memory is insufficient and related processing functions are not defined. 5 # ifndef THROW_OOM 6 # include <stdio. h> 7 # include <stdlib. h> 8 # define THROW_OOM fprintf (stderr, "out of memory \ n"); exit (1) 9 # endif10 11 # include <stdlib. h> 12 13 namespace Chenstl {14 15 // Level 1 space configurator, directly use mallloc to allocate memory 16 // use 17 class malloc_alloc {18 private: 19 static void * oom_malloc (size_t) when the space to be allocated is greater than MAX_BYTES; // declare Only the write type is allowed .. Now we know 20 static void * oom_realloc (void *, size_t); 21 static void (* malloc_oom_handler) (); // The function pointer 22 public when malloc processing is insufficient memory: 23 static void * allocate (size_t n); 24 static void decllocate (void * p); 25 26 static void * realloc (void * p, size_t new_sz ); 27 // when the memory is insufficient, the client needs to set handler28 static void set_malloc_oom_handler (void (* f) (); 29}; 30} 31 32 # endif
1 # include "malloc_alloc.h" 2 3 using namespace Chenstl; 4 void * malloc_alloc: allocate (size_t n) 5 {6 void * result = malloc (n ); 7 if (0 = result) result = oom_malloc (n); 8 return result; 9} 10 11 void malloc_alloc: decllocate (void * p) 12 {13 free (p); 14} 15 16 void * malloc_alloc: realloc (void * p, size_t new_sz) 17 {18 void * result = realloc (p, new_sz ); 19 if (0 = result) result = oom_realloc (p, new_sz); 20 return result; 21} 22 23 // when the memory is insufficient, the client needs to set handler24 void malloc_alloc :: callback (void (* f) () 25 {26 malloc_oom_handler = f; 27} 28 29 void (* malloc_alloc: malloc_oom_handler) () = 0; 30 31 void * malloc_alloc:: oom_malloc (size_t n) 32 {// constantly trying to get the memory 33 void * result; 34 for (;) // It is said that this is worse than while (1) better Results 35 {36 if (0 = malloc_oom_handler) THROW_OOM; 37 (* malloc_oom_handler) (); 38 result = malloc (n); 39 if (result) return result; 40} 41} 42 43 void * malloc_alloc: oom_realloc (void * p, size_t n) 44 {45 void * result; 46 (;;) 47 {48 if (0 = malloc_oom_handler) THROW_OOM; 49 (* malloc_oom_handler) (); 50 result = realloc (p, n); 51 if (result) return result; 52} 53}Malloc_alloc.cpp
If the required block exceeds bytes, use the first level. Otherwise, use the second-level memory pool for management. For ease of management, the configurator automatically increases the memory demand to a multiple of 8 (when 20 bytes are required, it is automatically adjusted to 24 bytes ). Use 16 freelist to manage the memory pool. To save space, use union
Union obj {// node construction of free-lists
Union obj * next;
Char client [1]; // visible to users
};
The code and steps for getting the memory are as follows:
Void * default_alloc: allocate (size_t n) {obj * result = 0; obj ** my_free_list = 0; if (n> MAX_BYTES) return malloc_alloc: allocate (n ); // find a suitable my_free_list = free_list + FREELIST_INDEX (n); result = * my_free_list; if (0 = result) {// no available freelist is found, retrieve the space from the memory pool: return refill (ROUND_UP (n);} // adjust freelist * my_free_list = result-> next; return result ;}View Code
When no block is available in the free list, call refill () to fill the free list space. The new space is taken from the memory pool (completed by chunk_alloc ). If the memory pool is not enough, malloc. If the System heap space is not enough, chunk_alloc () will find the free list with idle blocks and fill the memory in the public, if not, call the first-level configurator. The first-level configurator implements the new-handler mechanism. If the memory is insufficient, an exception is thrown.
# Ifndef _ DEFAULT_ALLOC_H # define _ DEFAULT_ALLOC_Hnamespace Chenstl {// use the memory pool to reduce the fragmentation class default_alloc {private: enum {ALIGN = 8}; enum {MAX_BYTES = 128 }; enum {NFREELISTS = 16}; // static const int ALIGN = 8; // static const int MAX_BYTES = 128; // static const int NFREELISTS = 16; // MAX_BYTES/ALIGN union obj {// union obj * next; char client [1] ;}; // freelist static obj * free_list [NFREELISTS]; static char * start_free; // the starting position of the memory pool static char * end_free; // The ending position of the memory pool static size_t heap_size; private: // raise bytes to a multiple of 8: static size_t ROUND_UP (size_t bytes) {return (bytes + ALIGN-1 )&~ (ALIGN-1);} // obtain the location of the appropriate block in freelist static size_t FREELIST_INDEX (size_t _ bytes) {return (_ bytes) + (size_t) ALIGN-1)/(size_t) ALIGN-1);} // returns an object of n size, other blocks with n size may be added to the free-list static void * refill (size_t n); // configure a large space, it can accommodate nobjs blocks of size // If nobjs blocks are not configured, nobjs may reduce static char * chunk_alloc (size_t size, int & nobjs); public: static void * allocate (size_t n); static void deallocate (void * p, size_t n); static void * realloc (void * p, size_t old_sz, size_t new_sz );};} # endifDefault_alloc.h
# Include "default_alloc.h" # include "malloc_alloc.h" using namespace Chenstl; default_alloc: obj * default_alloc: free_list [NFREELISTS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; char * default_alloc: start_free = 0; // The starting position of the memory pool char * default_alloc: end_free = 0; // The ending position of the memory pool size_t default_alloc: heap_size = 0; void * default_alloc :: allocate (size_t n) {obj * result = 0; obj ** my_free_list = 0; if (n> MAX_BYTES) return malloc_alloc: allocate (n); // find a suitable my_free_list = free_list + FREELIST_INDEX (n) in free lists; result = * my_free_list; if (0 = result) {// no available freelist is found, and the return refill (ROUND_UP (n) space is retrieved from the memory pool ));} // adjust freelist * my_free_list = result-> next; return result;} void default_alloc: deallocate (void * p, size_t n) {} // returns an object of n size, and may add other blocks of n to freelist // in ANSI c, void * cannot be added or subtracted, so chunk uses char * Void * default_alloc: refill (size_t n) {int objs = 20; char * chunk = chunk_alloc (n, objs); obj * next, * current; obj * result; obj ** my_free_list; if (1 = objs) // retrieve only one block return chunk; my_free_list = free_list + FREELIST_INDEX (n); result = (obj *) chunk; // return this part to the client // point freellist to the allocated Region * my_free_list = next = (obj *) chunk + n; for (int I = 1; I ++) {current = next; next = (obj *) (char *) next + n );/ /Note that next + n if (I = objs-1) {current-> next = 0; break;} else current-> next = next;} cannot be used directly ;} return result;} char * default_alloc: chunk_alloc (size_t size, int & nobjs) {char * result = 0; size_t Limit = size * nobjs; size_t bytes_left = end_free-start_free; // memory pool remaining space if (bytes_left> = total_bytes) {// The memory pool is sufficient to provide the required memory result = start_free; start_free + = total_bytes; return result;} else if (bytes _ Left> = size) {// The memory pool is sufficient to supply more than one block. nobjs = bytes_left/size; total_bytes = nobjs * size; result = start_free; start_free + = total_bytes; return result;} else {// neither can size_t bytes_to_get = 2 * total_bytes + ROUND_UP (heap_size> 4); if (bytes_left> 0) {// allocate the zero header of the memory pool to the appropriate freelist obj ** my_free_list = free_list + FREELIST_INDEX (bytes_left); (obj *) start_free)-> next = * my_free_list; * my_free_list = (Obj *) start_free;} start_free = (char *) malloc (bytes_to_get); if (! Start_free) {// The system heap memory is insufficient. Find unused freelist obj * p = 0; obj ** my_free_list = 0; for (int I = size; I <MAX_BYTES; ++ I) {my_free_list = free_list + FREELIST_INDEX (I); p = * my_free_list; if (0! = P) {// There are also unused freelist start_free = (char *) p; * my_free_list = p-> next; end_free = start_free + I; // recursive call, corrected nobjs return chunk_alloc (size, nobjs) ;}}// no memory is available. It is expected that the first-level new-handler or an exception end_free = 0 will be thrown; start_free = (char *) malloc_alloc: allocate (bytes_to_get);} heap_size + = bytes; end_free = start_free + bytes_to_get; return chunk_alloc (size, nobjs); // recursive call, corrected nobjs }}Default_alloc.cpp