上一篇没写完的代码,因为我用的是VS2013所以无法测试我的配置器,我是照着SGI的版本写的,所以不符合STL标准规范,而VS随身带的STL是符合STL规范的,所以我无法测试,等到我自己写好了迭代器,容器之后,就可以测试了,不过在这之前,我将专门用一篇文件来学习并且自己写一个内存池,然后将这个内存池部署到我的HJSTL里面,下面是完整的HJSTL 空间配置器代码 1.0.0,大规模模仿SGI,但是这没办法,到后面数据结构部分可能会加入更多我自己的东西,前面的部分再怎么搞也没有别人那么好,所以就献丑了,代码--->
/* * CopyRight (c) 2016 * HuJian in nankai edu. * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. Silicon Graphics makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. * * Time :2016/4/5 in nankai edu */ #ifndef _HJ_STL_ALLOC_H_ #define _HJ_STL_ALLOC_H_ #include<cstdio> #include<climits> #include<iostream> #include<cstddef> //if out of memory,just exit after print the info. #define _THROW_BAD_ALLOC cerr<<"out of memory"<<endl; exit(1); //this is the new-handler handler,using when oom void(*_malloc_alloc_oom_handler_hjstl)() = 0; //this is the first class of mmu in hjstl,this class will work //if the second dispatch the job to it. template<int inst> class _malloc_alloc_first{ private: static void* oom_malloc(size_t); //this function use to malloc and has the new-handler static void* oom_remalloc(void*, size_t);//re-malloc public: //this function is the first allocator of hjstl static void* allocate(size_t size) { void* result = malloc(size); //check and dispatch it to oom_malloc if oom if (0 == result) result = oom_malloc(size); return result; } //re-malloc,same as malloc static void* remallocate(void* old, size_t/*old mem size*/, size_t new_size) { void* result = realloc(old, new_size); if (0 == result) result = oom_remalloc(old, new_size); return result; } //de-allocate static void deallocate(void* mem, size_t size) { //we not use the memory pool,so just use free //but we will use the memory pool to manage the memory of //hjstl later free(mem); } //we can use this function to set the new handler static void(*set_malloc_handler(void(*handler)()))() { //get the old oom handler,and we will return it to process void(*old)() = _malloc_alloc_oom_handler_hjstl; //set the new handler _malloc_alloc_oom_handler_hjstl = handler; return (old); } };//end of malloc alloc first ///---impelment the first allocate of hjstl template<int inst> void* _malloc_alloc_first<inst>::oom_malloc(size_t size) { //this is the oom handler,this function will use this function when //out of memory void(*my_malloc_handler)(); void* result; for (;;){//i will loop to test till i get the memory my_malloc_handler = _malloc_alloc_oom_handler_hjstl; if (0 == my_malloc_handler) { _THROW_BAD_ALLOC; } //else,the handler defined,i can use it,run this handler (*my_malloc_handler)(); result = malloc(size); if (result) return result;//succeed!!! } } //same as malloc template<int inst> void* _malloc_alloc_first<inst>::oom_remalloc(void* old, size_t size) { void (* my_handler)(); void* result; for (;;){ my_handler = _malloc_alloc_oom_handler_hjstl; if (0 == myhandler) { _THROW_BAD_ALLOC; } (*my_handler)(); result = realloc(old, size); if (result) return result; } } //ok,i need to define a first allocate,and if the second //allocate can not do it,let me try! typedef _malloc_alloc_first<0> malloc_alloc_first_hjstl; //we do this,because we need to let the HJSTL standard with STL template<class Type,class HJALLOC> class STD_STL_Alloc{ public: static Type* allocate(size_t size){ return 0 == n ? 0 : (Type*)HJALLOC::allocate(size*sizeof(Type)); } static Type* allocate(){ return (Type*)HJALLOC::allocate(sizeof(Type)); } static void deallocate(Type* mem,size_t size){ if (size != 0){ HJALLOC::deallocate(mem,size*sizeof(Type)); } } static void deallocate(Type* mem){ HJALLOC::deallocator(mem,sizeof(mem)); } }; //ok,start to write the second allocator //and some auxiliary variable neeed to define here #define _ALIGN 8 //the min mem block #define _MAX_BYTES 128 //the max mem block #define _NFREELISTS _MAX_BYTES/_ALIGN //this is the num of free list template<int inst>//no thread supposed class _malloc_alloc_second{ private: //round up a size static size_t HJSTL_ROUND_UP(size_t bytes){ //ok,i use the SGI STL's round up method,it nice return (((bytes)+_ALIGN - 1) & ~(_ALIGN - 1)); } //this function will find the free list's position in the array actually static size_t HJSTL_FREELIST_INDEX(size_t bytes){ //i just copy the sgi stl's code here. return (((bytes)+_ALIGN - 1) / _ALIGN - 1); } //this is the free list's node strcture //this is a usion.just copy the sgi stl's union free_list_node{ free_list_node* free_list_link;//store the next free list char data[1];//if assigned,this is the user's data }; //this is the array of free lists static free_list_node* free_list[_NFREELISTS]; //return an object of size n,and this function will re-fill the //free list,update the free list array . static void* refill(size_t size); //memory pool,and allocate a chunk for nobjs of size 'size' //if the memory of pool is not so enough,this function will //return the real num of nobjs static char* chunk_alloc(size_t size, int &nobjs); //this is a sample memory pool static char* pool_free_start; static char* pool_free_end; static size_t heap_size; //the second allocate static void* allocate(size_t size) { free_list_node* my_free_list; free_list_node* result; //dispatch the job,if the ask memory bigger _MAX_BYTES,use //the first allocate,else use the second allocate if (size > (size_t)_MAX_BYTES){ return (malloc_alloc_first_hjstl::allocate(size)); } //else ,use the second allocate to do this job //find the aim-free list my_free_list = free_list + HJSTL_FREELIST_INDEX(size); //now,the result is the header pointer of this list result = *my_free_list; if (0 == result){//shirt,this list is empty,i will call refill to help me void* r = refill(HJSTL_ROUND_UP(size)); return r; } //else,this free list is not empty,just use the header pointer //and change the free list. *my_free_list = result->free_list_link; return result; } //the second deallocate static void deallocate(void* mem, size_t size) { free_list_node* my_free_list; free_list_node* new_header_pointer = (free_list_node*)mem; //dispatch the job if (size > (size_t)_MAX_BYTES){ malloc_alloc_first_hjstl::deallocate(mem, size); return; } //else,solve it. //first of all,i will find the free list's position my_free_list = free_list + HJSTL_FREELIST_INDEX(size); //change the list new_header_pointer->free_list_link = my_free_list; *my_free_list = new_header_pointer; return; } //this is the second reallocate static void* reallocate(void* old, size_t old_size, size_t new_size); };//end of second allocator //heihei,this is the default alloc,we will use this alloc in our project typedef _malloc_alloc_second<0> hjstl_alloc; //the follow function is the memory pool of hjstl //and this function will allocate a large memory chunk in //order to avoid fragement. template<int inst> char* _malloc_alloc_second<inst>::chunk_alloc(size_t size, int&nobjs) { char* result; //the size the the num of each objs size_t total_bytes = size*nobjs; //the left bytes current size_t left_bytes = pool_free_end - pool_free_start; //then,if the memory pool's memory is enough,just give it and update the memory pool. if (total_bytes <= left_bytes){ result = pool_free_start; pool_free_start += total_bytes; return result; } //else ,the pool's memory is not enough to allocate. //but the pool's memory left at least 1 size memory //just return it. //but,this part maybe left some fragment in the pool //so,before we re-fill this pool,we need to handle the lefe mem in pool else if (left_bytes >= size){ //calc the counts we can allocate nobjs = left_bytes / size; //update the pool's size total_bytes = nobjs*size; result = pool_free_start; pool_free_start += total_bytes; return result; } //ok,the pool's memory is not enough to allocate 1 obj //then,we need to re-alloc memory to fill pool from os //but before doing this job,we need to check the pool's left memory //and handle it.<append the left mem to free list> else{ size_t ask_bytes = 8* total_bytes + HJSTL_ROUND_UP(heap_size >> 4); //is any fragments in pool's if (left_bytes > 0){ free_list_node* my_free_list = free_list + HJSTL_FREELIST_INDEX(left_bytes); //append this fragment to free list ((free_list_node*)pool_free_start)->free_list_link = *my_free_list; *my_free_list = (free_list_node*)pool_free_start; } //is any little fragment in pool now? if it is,just free it if (left_bytes<_ALIGN){ #ifdef _HJSTL_DUBUG_ cout<<"little fragments left pool now...<in function chunk_alloc>"<<endl; #endif int free_len = 0; while (free_len < left_bytes){ free(pool_free_start); pool_free_start++; } } //it's time to re-allocate a big memory from os pool_free_start = (char*)malloc(ask_bytes); //but if the malloc fail if (0 == pool_free_start){ free_list_node* my_free_list, *find_list; //ok,we need to check the free lists and get some aproval size's //node to free,and re-try malloc,loop till we get the memory //but we will down to half ask to do it. if (ask_bytes / 2 && ask_bytes>(2* total_bytes + HJSTL_ROUND_UP(heap_size >> 4))) ask_bytes /= 2; for (int i = size; i <= _MAX_BLOCKS; i += _ALIGN){ my_free_list = free_list + HJSTL_FREELIST_INDEX(i); find_list = *my_free_list; if (0 != find_list){ //free an node of this list *my_free_list = find_list->free_list_link; //update the pool's size pool_free_start = (char*)find_list; pool_free_end = pool_free_start + i; //re-try return (chunk_alloc(size, njobs)); } }// end of for loop //ok,you need to know we have no choice but ask first-allocate for help pool_free_end = 0; pool_free_start = (char*)malloc_alloc_first_hjstl::allocate(ask_bytes); } //well,if the program run to here,it say i have asked first-allocate for help //and now i have enough memory to give you //so,just adjust the pool's size and heap's size heap_size += ask_bytes; pool_free_end = pool_free_start + ask_bytes; //you can re-call self to complete the job now. //cause the pool's size is enough to work. return (chunk_alloc(size, nobjs)); }//end of re-allocate } //this is the re-fill function,and this function will adjust the free list //and the main operator is call the chunk_alloc.. template<int inst> void* _malloc_alloc_second<inst>::refill(size_t size) { //the default nodes is 20,but you can adjust the num int default_nodes = 20; //allocate memory from pool char* chunk = chunk_alloc(size, default_nodes); free_list_node* my_free_list, *result; free_list_node* current_node, *next_node; //if the chunk_alloc just return 1 nodes,it's ok to use it,but do not //need to adjust the free list if (1 == default_nodes) return chunk; //else,not only return 1 node,but also adjust the free list my_free_list = free_list + HJSTL_FREELIST_INDEX(size); result = (free_list_node*)chunk;//just get one node,and return to user //connect the list,the first node give the user //the next_node pointer to the start of chunk we can use to adjust free list next_node = (free_list_node*)(chunk + size); *my_free_list = next_node; for (int i = 1;; i++){ current_node = next_node; next_node = (free_list_node*)((char*)next_node + size); //if this is the last node if (i == default_nodes - 1){ current_node->free_list_link = 0; } else{ //this is not the last node current_node->free_list_link = next_node; } } return (result); } //re-allocate template<int inst> void* _malloc_alloc_second<inst>::reallocate(void* oldmem, size_t oldsz, size_t newsz) { void* result; //if the size is no change.just return if (HJSTL_ROUND_UP(oldsz) == HJSTL_ROUND_UP(newsz)) return oldmem; //if the new size <old size,just return if (oldsz > newsz) return oldmem; //else,malloc,and copy data result = allocate(newsz); memcpy(rsult, oldmem, newsz); deallocate(oldmem, oldsz); return result; } #endif //end of _HJ_STL_ALLOC_H_