SGISTL原始碼閱讀一 空間配置器上(第一級配置器)
阿新 • • 發佈:2018-11-11
SGISTL原始碼閱讀一 空間配置器上(第一級配置器)
引入
我們所熟知的C++記憶體配置操作一般為
class A {}
A* pa = new A(); //1.分配記憶體 2.構造物件
delete pa; //1.物件析構 2.釋放記憶體
其中new
完成了兩個操作
1.呼叫operator new
配置記憶體
2.呼叫A::A()構造物件
這樣做沒有考慮到任何效率上的強化,如果有些空間根本不會被用到,那麼構造物件完全就是一種浪費。
而STL中的alloc將new
所完成的操作拆分開來,SGISTL原始碼中有兩個檔案,stl_alloc.h
負責記憶體空間的配置與釋放,stl_construct.h
SGI特殊的空間配置器
物件構造前的空間配置和物件析構後的空間釋放,由stl_alloc.h
負責。
考慮到小型區塊可能造成的記憶體破碎問題,SGI設計了雙層級配置器。
第一級配置器用於處理大於128bytes的情況,即申請大的記憶體,第二級配置器用於申請小記憶體。
第一級配置器(__malloc_alloc_template)
直接使用malloc()
和 free()
即可,我們來深入原始碼探究。
//這裡用到了模板全特化技術 template <int inst> class __malloc_alloc_template { private: /* *oom(out of memory) *下面的函式用於處理記憶體不足的情況 */ static void *oom_malloc(size_t); static void *oom_realloc(void *, size_t); #ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG //函式指標,指向引數和返回值均為空的函式 static void (* __malloc_alloc_oom_handler)(); #endif public: //申請n個大小的空間 static void * allocate(size_t n) { void *result = malloc(n); if (0 == result) result = oom_malloc(n); return result; } //釋放空間 static void deallocate(void *p, size_t /* n */) { free(p); } //重新申請空間 static void * reallocate(void *p, size_t /* old_sz */, size_t new_sz) { void * result = realloc(p, new_sz); if (0 == result) result = oom_realloc(p, new_sz); return result; } /* *這是一個返回值為函式指標的指標函式(傳送門:https://blog.csdn.net/lyn_00/article/details/83549655) *模擬C++的set_new_handler() *它的作用是可以讓使用者自己定義記憶體不足時的處理函式,並返回舊的處理方法 */ static void (* set_malloc_handler(void (*f)()))() { void (* old)() = __malloc_alloc_oom_handler; __malloc_alloc_oom_handler = f; return(old); } };
以下是處理記憶體不足的情況
// malloc_alloc out-of-memory handling #ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG template <int inst> void (* __malloc_alloc_template<inst>::__malloc_alloc_oom_handler)() = 0; #endif template <int inst> void * __malloc_alloc_template<inst>::oom_malloc(size_t n) { //區域性函式指標,用於指向使用者字定義處理函式 void (* my_malloc_handler)(); void *result; /* *如果使用者沒有定義記憶體不足時的處理函式,則丟擲一個異常,反之,則申請到記憶體正常退出 *我們可以注意到這是一個死迴圈,但是也不難理解,因為必須對記憶體不足這種情況做好處理 */ for (;;) { my_malloc_handler = __malloc_alloc_oom_handler; if (0 == my_malloc_handler) { __THROW_BAD_ALLOC; } (*my_malloc_handler)(); result = malloc(n); if (result) return(result); } } //realloc和malloc類似 template <int inst> void * __malloc_alloc_template<inst>::oom_realloc(void *p, size_t n) { void (* my_malloc_handler)(); void *result; for (;;) { my_malloc_handler = __malloc_alloc_oom_handler; if (0 == my_malloc_handler) { __THROW_BAD_ALLOC; } (*my_malloc_handler)(); result = realloc(p, n); if (result) return(result); } } //直接將引數inst指定為0 typedef __malloc_alloc_template<0> malloc_alloc;
總結
以上主要對SGI中空間配置器的第一級配置器進行了分析。它如何申請釋放記憶體,以及對記憶體不足時的處理。第二級配置器比第一級配置器要複雜得多,將會在下一篇部落格中介紹。