zoukankan      html  css  js  c++  java
  • 自己动手实现STL 01:内存配置器的实现(stl_alloc.h)

    一、前言

      在STL中,容器是其中的重中之重,基本的STL中的算法,仿函数等都是围绕着容器实现的功能。而,内存配置器,是容器的实现的基础。所以,我第一次要去编写便是内存配置器的实现。在STL中,内存配置器的实现是在stl_alloc.h中。

    二、配置器原理简要介绍

      在SGI STL中配置分为两级,第一级配置器和第二级配置器。两者关系如下:

    图1:第一级配置器和第二级配置器

      在SGI STL中内存的配置器分为两级,第一级配置器和第二级配置器。第一级配置器就是,直接调用系统的malloc分配内存。对于小于128byte的内存分配请求,我们使用第二级内存配置器。第二级内存配置器是一个内存池,其中共有16个已分配好的区块形成的链表。这16个链表的中区块的大小依次是8,16,24....128byte,都8的倍数。每次请求小于等于128byte时,把请求的大小上调到最接近的8的倍数,比如,7就上调为8,30就上调为32,然后找到对应大小区块的链表,从中取下一个区块返回给请求。

      第二级配置器使用内存池的好处就是,可以避免太多小额区块造成的内存破碎。同时,每次分配内存都需要调用malloc去分配,malloc调用的消耗的时间等资源是一定的,对于大区块的分配这样的消耗的时间等资源,是没有什么的。但是对于小额区块的,它的消耗就显得太不值的了。我们可以采用一次预分配一块连续的大区块,把它串成一个定额大小的区块链表,(8的倍数字节),下次使用的时候,从对应预分配的区块链表中找一个能够满足大小的,最接近的区块直接返回给请求,这样就可以避免对于小区块的malloc调用。同时对于小区块的释放,可以直接把它加入到内存池中对应大小的链表中即可。

    图2:把连续大区块串成小额区块

      在第二级配置器中维持一个free_list[16]数组,其中存储着8-128byte各种大小区块的链表的头节点地址。

    图3:free_list[16]结构

      每次分配只要从适当大小的链表中取出第一个节点,返回给请求,让free_list对应的位置的保存链表的下一个节点地址。释放的时候,对于小于等于128byte的区块,只要把它插入对应大小区块链表的头,然后调整保存的链表头结点的地址就可以了。当需求大小区块的使用完了的时候,可以利用malloc一次分配适当大小的大区块,然后把它分割为对应大小的小区块,在把它们串联起来形成链表,把第一个节点地址存入对应的free_list的位置中。

    三、实现源代码

      上面只是配置器的简介,在源码中有详细的注释。源码如下:

      1 /*************************************************************************
      2     > File Name: stl_alloc_wjzh.h
      3     > Author: wjzh
      4     > Mail: wangjzh_1@163.com 
      5     > Created Time: 2014年10月31日 星期五 16时06分23秒
      6  ************************************************************************/
      7 
      8 #ifndef __SGI_STL_INTERNAL_ALLOC_WJZH_H
      9 #define __SGI_STL_INTERNAL_ALLOC_WJZH_H
     10 
     11 #ifdef __SUNPRO_CC
     12 #    define __PRIVATE public
     13 #else
     14 #    define __PRIVATE private
     15 #endif
     16 
     17 #ifdef __STL_STATIC_TEMPLATE_MEMBER_BUG
     18 #    define __USE_MALLOC
     19 #endif
     20 
     21 #if 0
     22 #    include <new>
     23 #    define __THROW_BAD_ALLOC throw bad_alloc
     24 #elif !defined(__THROW_BAD_ALLOC)
     25 //#    include <iostream.h>
     26 #include <iostream>
     27 #    define __THROW_BAD_ALLOC std::cerr << "out of memory" << std::endl; exit(1)
     28 #endif
     29 
     30 #ifndef __ALLOC
     31 #    define __ALLOC alloc
     32 #endif
     33 #ifdef __STL_WIN32THREADS
     34 #    include <windows.h>
     35 #endif
     36 
     37 #include <stddef.h>
     38 #include <stdlib.h>
     39 #include <string.h>
     40 #include <assert.h>
     41 #ifndef __RESTRICT
     42 #    define __RESTRICT
     43 #endif
     44 
     45 #if !defined(__STL_PTHREADS) && !defined(_NOTHREADS) 
     46  && !defined(__STL_SGI_THREADS) && !defined(__STL_WIN32THREADS)
     47 #    define _NOTHREADS
     48 #endif
     49 
     50 #ifdef __STL_PTHREADS
     51 #    include <pthread.h>
     52 #    define __NODE_ALLOCATOR_LOCK 
     53         if (threads) pthread_mutex_lock(&__node_allocator_lock)
     54 #    define __NODE_ALLOCATOR_UNLOCK 
     55         if (threads) pthread_mutex_unlock(&__node_allocator_lock)
     56 #    define __NODE_ALLOCATOR_THREADS true
     57 #    define __VOLATILE volatile
     58 # endif
     59 # ifdef __STL_WIN32THREADS
     60 #    define __NODE_ALLOCATOR_LOCK 
     61         EnterCriticalSection(&__node_allocator_lock)
     62 #    define __NODE_ALLOCATOR_UNLOCK 
     63         LeaveCriticalSection(&__node_allocator_lock)
     64 #    define __NODE_ALLOCATOR_THREADS true
     65 #    define __VOLATILE volatile
     66 # endif
     67 
     68 # ifdef __STL_SGI_THREADS
     69     extern "C" {
     70         extern int __us_rsthread_malloc;
     71     }
     72 #    define __NODE_ALLOCATOR_LOCK if (threads && __us_rsthread_malloc) 
     73 { __lock(&__node_allocator_lock);    }
     74 #    define __NODE_ALLOCATOR_UNLOCK if(threads && __us_rsthread_malloc) 
     75 { __unlcok(&__node_allocator_lock);    }
     76 #    define __NODE_ALLOCATOR_THREADS true
     77 #    define __VOLATILE volatile
     78 # endif
     79 
     80 # ifdef _NOTHREADS
     81 #    define __NODE_ALLOCATOR_LOCK
     82 #    define __NODE_ALLOCATOR_UNLOCK
     83 #    define __NODE_ALLOCATOR_THREADS false
     84 #    define __VOLATILE
     85 # endif
     86 
     87 __STL_BEGIN_NAMESPACE
     88 
     89 #if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
     90 #pragma set woff 1174
     91 #endif
     92 
     93 #ifdef __STL_STATIC_TEMPLATE_MEMBER_BUG
     94 #    ifdef __DECLARE_GLOBALS_HERE
     95         void (* __malloc_alloc_oom_handler)() = 0;
     96 #else
     97         extern void (* __malloc_alloc_oom_handler)();
     98 # endif
     99 #endif
    100 
    101 template <int inst>
    102 class __malloc_alloc_template {
    103     private:
    104         static void *oom_malloc(size_t);
    105         static void *oom_realloc(void *, size_t);
    106 #ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
    107         static void (* __malloc_alloc_oom_handler)();
    108 #endif
    109     public:
    110         static void* allocate(size_t n)
    111         {
    112             void *result = malloc(n);
    113             if (0 == result) result = oom_malloc(n);
    114             return result;
    115         }
    116 
    117         static void deallocate(void *p, size_t)
    118         {
    119             free(p);
    120         }
    121 
    122         static void * reallocate(void *p, size_t , size_t new_sz)
    123         {
    124             void *result = realloc(p, new_sz);
    125             if (0 == result) result = oom_realloc(p, new_sz);
    126             return result;
    127         }
    128 
    129         static void (* set_malloc_handler(void (*f)()))()
    130         {
    131             void (* old)() = __malloc_alloc_oom_handler;
    132             __malloc_alloc_oom_handler = f;
    133             return(old);
    134         }
    135 
    136 };
    137 
    138 // malloc_alloc out-of-memory handling
    139 // 分配内存时,没有内存时的处理
    140 
    141 #ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
    142 template <int inst>
    143 void (* __malloc_alloc_template<inst>::__malloc_alloc_oom_handler)() = 0;
    144 #endif
    145 
    146 template <int inst>
    147 void * __malloc_alloc_template<inst>::oom_malloc(size_t n)
    148 {
    149     void (* my_malloc_handler)();
    150     void *result;
    151     for (;;)
    152     {
    153         my_malloc_handler = __malloc_alloc_oom_handler;
    154         if (0 == my_malloc_handler) { __THROW_BAD_ALLOC; }
    155         (*my_malloc_handler)();
    156         result = malloc(n);
    157         if (result) return (result);
    158     }
    159 }
    160 
    161 template <int inst>
    162 void * __malloc_alloc_template<inst>::oom_realloc(void *p, size_t n)
    163 {
    164     void (* my_malloc_handler)();
    165     void *result;
    166 
    167     for (;;)
    168     {
    169         my_malloc_handler = __malloc_alloc_oom_handler;
    170         if (0 == my_malloc_handler) { __THROW_BAD_ALLOC; }
    171         (*my_malloc_handler)();
    172         result = realloc(p, n);
    173         if (result) return (result);
    174     }
    175 }
    176 
    177 typedef __malloc_alloc_template<0> malloc_alloc;
    178 
    179 template<class T, class Alloc>
    180 class simple_alloc
    181 {
    182     public:
    183         static T *allocate(size_t n)
    184         {
    185             return 0 == n ? 0 : (T*) Alloc::allocate(n * sizeof(T));
    186         }
    187         static T *allocate(void)
    188         {
    189             return (T*) Alloc::allocate(sizeof(T));
    190         }
    191         static void deallocate(T *p, size_t n)
    192         {
    193             if (0 != n) Alloc::deallocate(p, n * sizeof(T));
    194         }
    195         static void deallocate(T *p)
    196         {
    197             Alloc::deallocate(p, sizeof(T));
    198         }
    199 };
    200 
    201 // Allocator adaptor to check size arguments for debugging.
    202 template <class Alloc>
    203 class debug_alloc
    204 {
    205     private:
    206         enum { extra = 8};    // Size of space used to store size. Note
    207                     // that this must be large enough to preserve
    208                     // alignment.
    209 
    210     public:
    211         static void * allocate(size_t n)
    212         {
    213             char *result = (char *)Alloc::allocate(n + extra);
    214             *(size_t *)result = n;    //前size_t大小用来记录result的大小,实际预分配了extra个字节,用来存储大小,
    215                         //但是只用size_t字节,因为不同系统size_t大小不同,8个字节足够满足所有系统了
    216             return result + extra;
    217         }
    218         
    219         static void deallocate(void *p, size_t n)
    220         {
    221             char * real_p = (char *)p - extra;
    222             assert(*(size_t *)real_p == n);
    223             Alloc::deallocate(real_p, n + extra);
    224         }
    225 
    226         static void * reallocate(void *p, size_t old_sz, size_t new_sz)
    227         {
    228             char * real_p = (char *)p - extra;
    229             assert(*(size_t *)real_p == old_sz);
    230             char * result = (char *)
    231                             Alloc::reallocate(real_p, old_sz + extra, new_sz+ extra);
    232             *(size_t *)result = new_sz;
    233             return result + extra;
    234         }
    235 
    236 };
    237 
    238 #ifdef __USE_MALLOC
    239 
    240 typedef malloc_alloc alloc;
    241 typedef malloc_alloc single_client_alloc;
    242 
    243 #else
    244 
    245 //下面是第二级配置器
    246 //主要是维护一个内存池,用来小于128byte的小型区块内存的分配
    247 //其中,有多个链表,各链表中的node大小从8-128byte,都是8的倍数
    248 //分配时,不是8的倍数,上调至最近的8的倍数,
    249 //然后从相应链表中取下一个对应大小的node分配给请求
    250 #ifdef __SUNPRO_CC
    251     enum {__ALIGN = 8};  //小型区块的上调边界
    252     enum {__MAX_BYTES = 128};   //小型区块的上限
    253     enum {__NFREELISTS = __MAX_BYTES/__ALIGN};
    254 #endif
    255 
    256 //第二级配置器
    257 template <bool threads, int inst>
    258 class __default_alloc_template
    259 {
    260     private:
    261 # ifndef __SUNPRO_CC
    262     enum {__ALIGN = 8};  //小型区块的上调边界
    263     enum {__MAX_BYTES = 128};   //小型区块的上限
    264     enum {__NFREELISTS = __MAX_BYTES/__ALIGN};
    265 # endif
    266     //大小上调至8的倍数
    267     static size_t ROUND_UP(size_t bytes)
    268     {
    269         return (((bytes) + __ALIGN-1) & ~(__ALIGN - 1));
    270     }
    271 __PRIVATE:
    272     union obj
    273     {
    274         union obj * free_list_link;  //用于在链表中指向下一个节点
    275         char client_data[1]; //用于存储实际区块的内存地址,由于这是一个union,很好的节约了这个数据的内存
    276     };
    277     private:
    278 # ifdef __SUNPRO_CC
    279     static obj * __VOLATILE free_list[];
    280 # else
    281     static obj * __VOLATILE free_list[__NFREELISTS];
    282 # endif
    283     static size_t FREELIST_INDEX(size_t bytes)
    284     {
    285         return (((bytes) + __ALIGN-1)/__ALIGN - 1);
    286     }
    287 
    288     //返回大小为n的对象,并可能加入大小为n的其他区块到free list
    289     static void *refill(size_t n);
    290     //配置一块空间,可容纳nobjs个大小为"size"的区块
    291     //如果配置nobjs个区块有所不便,nobjs可能会降低
    292     static char *chunk_alloc(size_t size, int &nobjs);
    293 
    294     //chunk 分配、配置的状态
    295     static char *start_free; //内存池起始位置。只在chunk_alloc()中变化
    296     static char *end_free;   //内存池结束位置。只在chunk_alloc()中变化
    297     static size_t heap_size;
    298 /*
    299 # ifdef __STL_SGI_THREADS
    300     static volatile unsigned long __node_allocator_lock;
    301     static void __lock(volatile unsigned long *);
    302     static inline void __unlock(volatile unsigned long *);
    303 # endif
    304 */
    305 
    306 # ifdef __STL_PTHREADS
    307     static pthread_mutex_t __node_allocator_lock;
    308 # endif
    309 
    310 # ifdef __STL_WIN32THREADS
    311     static CRITICAL_SECTION __node_allocator_lock;
    312     static bool __node_allocator_lock_initialized;
    313 
    314     public:
    315         __default_alloc_template()
    316         {
    317             //假定第一个构造函数的调用在线程启动起
    318             if (!__node_allocator_lock_initialized)
    319             {
    320                 InitializedCriticalSection(&__node_allocator_lock);
    321                 __node_allocator_lock_initialized = true;
    322             }
    323         }
    324     private:
    325 # endif
    326 
    327         class lock
    328         {
    329             public:
    330                 lock() { __NODE_ALLOCATOR_LOCK; }
    331                 ~lock() { __NODE_ALLOCATOR_UNLOCK; }
    332         };
    333         friend class lock;
    334     public:
    335         //n必须大于0
    336         static void * allocate(size_t n)
    337         {
    338             obj * __VOLATILE * my_free_list;
    339             obj * __RESTRICT result;
    340 
    341             //需要分配的大小大于二级配置器的__MAX_BYTES,直接使用第一级配置器
    342             if (n > (size_t) __MAX_BYTES)
    343             {
    344                 return(malloc_alloc::allocate(n));
    345             }
    346             my_free_list = free_list + FREELIST_INDEX(n); //找到比需要分配的大小大,且最接近的大小块所在的链表所在free_list数组中的位置
    347             
    348             //如果支持线程,定义lock
    349 #        ifndef _NOTHREADS
    350             lock lock_instance;
    351 #        endif
    352             result = *my_free_list;  //取出找的对应链表的指向第一个节点的指针
    353             if (result == 0)    //对应的链表中没有剩余未分配的节点区块
    354             {
    355                 void *r = refill(ROUND_UP(n));    //再从内存池中分配一批,需求大小的区块(实际大小是请求大小上调至8的倍数后的数值),
    356                                 //然后,放入对应链表,待分配给请求
    357                 return r;
    358             }
    359             //如果对应大小区块的链表中不为空,还有待分配的区块,取出第一个节点
    360             *my_free_list = result -> free_list_link;
    361             return (result);
    362         };
    363 
    364         //p不可以是0
    365         static void deallocate(void *p, size_t n)
    366         {
    367             obj *q = (obj *)p;
    368             obj * __VOLATILE * my_free_list;
    369 
    370             //大于区块大小上限的,直接调用第一级配置器释放
    371             if (n > (size_t) __MAX_BYTES)
    372             {
    373                 malloc_alloc::deallocate(p, n);
    374                 return;
    375             }
    376             my_free_list = free_list + FREELIST_INDEX(n);
    377             //需要修改my_free_list,如果支持线程,那么需要加上互斥锁
    378 #            ifndef _NOTHREADS
    379             lock lock_instance;
    380 #            endif
    381 
    382             //头插法,插入对应大小的区块链表
    383             q -> free_list_link = *my_free_list;
    384             *my_free_list = q;
    385             //lock是静态对象,到此,将自动析构销毁,在其析构函数中,会释放锁
    386         }
    387 
    388         static void *reallocate(void *p, size_t old_sz, size_t new_sz);
    389 
    390 };
    391 
    392 typedef __default_alloc_template<__NODE_ALLOCATOR_THREADS, 0> alloc;
    393 typedef __default_alloc_template<false, 0> single_client_alloc;
    394 
    395 
    396 // 我们从大的chunks中分配内存,是为了避免使用malloc太频繁了
    397 // 假设size已经适当上调至8的倍数
    398 // 我持有allocation lock
    399 // 注意参数objs 是pass by reference
    400 template <bool threads, int inst>
    401 char *
    402 __default_alloc_template<threads, inst>::chunk_alloc(size_t size, int& nobjs)
    403 {
    404     char * result;
    405     size_t total_bytes = size * nobjs;
    406     size_t bytes_left = end_free - start_free;    //内存池剩余空间
    407 
    408     if (bytes_left >= total_bytes)
    409     {
    410         //内存池中剩余的空间足够满足需求量
    411         result = start_free;
    412         start_free += total_bytes;
    413         return(result);
    414     }
    415     else if (bytes_left >= size)
    416     {
    417         //内存池剩余空间不能完全满足需求量,但足够供应一个及以上的区块
    418         nobjs = bytes_left/size;
    419         total_bytes = size * nobjs;
    420         result = start_free;
    421         start_free += total_bytes;
    422         return (result);
    423     }
    424     else
    425     {
    426         //内存池连一个区块的大小都无法满足
    427         size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4);
    428         //以下试着让内存池中的残余零头还有利用价值
    429         if (bytes_left > 0)
    430         {
    431             //内存池中内还有一些零头,先配给适当的free list
    432             //首先寻找适当的free list
    433             obj * __VOLATILE * my_free_list = 
    434                     free_list + FREELIST_INDEX(bytes_left);
    435 
    436             //调整free list,将内存池中残余的空间编入
    437             ((obj *)start_free) -> free_list_link = *my_free_list; 
    438             *my_free_list = (obj *)start_free;
    439         }
    440 
    441         //配置heap空间,用来补充内存池
    442         start_free = (char *)malloc(bytes_to_get);
    443         if (0 == start_free)
    444         {
    445             //如果heap空间不足,malloc()失败
    446             int i;
    447             obj * __VOLATILE *my_free_list, *p;
    448             //试着检视我们手上的东西。这不会造成伤害。我们不打算尝试配置
    449             //较小的区块,因为那在多线程机器上容易导致灾难
    450             //以下搜索适当的free list
    451             //所谓适当是指“尚有未用区块,且区块够大”之free list
    452             for (i = size; i <= __MAX_BYTES; i += __ALIGN)
    453             {
    454                 my_free_list = free_list + FREELIST_INDEX(i);
    455                 p = *my_free_list;
    456                 if (0 != p)
    457                 {
    458                     //free list内尚有未用区块
    459                     //调整free list以释放出未用的区块到内存池
    460                     *my_free_list = p -> free_list_link;
    461                     start_free = (char *)p;
    462                     end_free = start_free + i;
    463                     // 此时内存池已经有内存了
    464                     // 递归调用自己,为了修正objs
    465                     return chunk_alloc(size, nobjs);
    466                     //注意,任何残余的零头终将被编入适当的free list中备用
    467                     
    468                 }
    469             }
    470             end_free = 0;  //如果出现意外(山穷水尽,到处都没有内存可用了)
    471             //调用第一级配置器,看看out-of-memory机制能否尽点力
    472             start_free = (char *)malloc_alloc::allocate(bytes_to_get);
    473             //这会导致抛出异常,或内存不足的情况获得改善
    474         }
    475         heap_size += bytes_to_get;
    476         end_free = start_free + bytes_to_get;
    477         //递归调用自己,为了修正objs
    478         return chunk_alloc(size, nobjs);
    479     }
    480 }
    481 
    482 
    483 
    484 // 返回一个大小为n的对象,并且有时候会为适当的free list 增加节点
    485 // 假设n已经适当上调至8的倍数
    486 // 我们持有allocation lock
    487 template <bool threads, int inst>
    488 void* __default_alloc_template<threads, inst>::refill(size_t n)
    489 {
    490     int nobjs = 20;  //默认一次分配20个需求大小的区块
    491     char * chunk = chunk_alloc(n, nobjs); //chunk是分配的空间的开始地址,令其类型为char *,主要是因为一个char的大小正好是一个byte
    492     obj * __VOLATILE *my_free_list;
    493     obj * result;
    494     obj * current_obj, * next_obj;
    495     int i;
    496 
    497     //如果只获得一个区块,这个区块就分配给调用者,free list 无新节点
    498     if (1 == nobjs) return chunk;
    499     //否则准备调整free list,纳入新节点
    500     my_free_list = free_list + FREELIST_INDEX(n);
    501 
    502     //以下在chunk空间内建立free list
    503     result = (obj *)chunk;  //这一块准备返回给客端
    504     // 以下导引free list 指向新配置的空间(取自内存池)
    505     
    506     //由于chunk是char*,所以加上n,就表示走过n个char,
    507     //一个char正好是一个byte,所以chunk+n现在指向第二个区块
    508     *my_free_list = next_obj = (obj *)(chunk + n); 
    509     for (i = 1; ; ++i)
    510     {
    511         // 从1开始,因为第0个将返回给客端
    512         current_obj = next_obj;
    513         // 每次移动n个char,正好是n个byte,所以正好指向下个区块
    514         next_obj = (obj *)((char *)next_obj + n);
    515         if (nobjs - 1 == i)
    516         {
    517             // 已经遍历完,此时next_obj指向的内存已经超出我们分配的大小了
    518             // 不属于我们的内存
    519             current_obj -> free_list_link = 0;
    520             break;
    521         }
    522         else
    523         {
    524             current_obj -> free_list_link = next_obj;
    525         }
    526     }
    527     return result;
    528 }
    529 
    530 
    531 template<bool threads, int inst>
    532 void*
    533 __default_alloc_template<threads, inst>::reallocate(void *p,
    534                                                     size_t old_sz,
    535                                                     size_t new_sz)
    536 {
    537     void * result;
    538     size_t copy_sz;
    539 
    540     if (old_sz > (size_t) __MAX_BYTES && new_sz > (size_t) __MAX_BYTES)
    541     {
    542         return realloc(p, new_sz);
    543     }
    544     if (ROUND_UP(old_sz) == ROUND_UP(new_sz)) return p;
    545     result = allocate(new_sz);
    546     copy_sz = new_sz > old_sz ? old_sz : new_sz;
    547     memcpy(result, p, copy_sz);
    548     deallocate(p, old_sz);
    549     return result;
    550 
    551 }
    552 
    553 #ifdef __STL_PTHREADS
    554     template <bool threads,int inst>
    555     pthread_mutex_t
    556     __default_alloc_template<threads, inst>::__node_allocator_lock
    557         = PTHREAD_MUTEX_INITIALIZER;
    558 #endif
    559 
    560 #ifdef __STL_WIN32THREADS
    561         template <bool threads, int inst> CRITICAL_SECTION
    562         __default_alloc_template<threads, inst>::__node_allocator_lock;
    563 
    564         template <bool threads, int inst> bool
    565         __default_alloc_template<threads, inst>::__node_allocator_lock_initialized
    566             = false;
    567 #endif
    568 
    569 //省略了通用lock的实现(即不使用pthread,也没有win32thread)
    570 
    571 template <bool threads, int inst>
    572 char *__default_alloc_template<threads, inst>::start_free = 0; //设置初始值
    573 
    574 template <bool threads, int inst>
    575 char *__default_alloc_template<threads, inst>::end_free = 0; //设置初始值
    576 
    577 template <bool threads, int inst>
    578 size_t __default_alloc_template<threads, inst>::heap_size = 0; //设置初始值
    579 
    580 //初始化16种大小的区块链表为空
    581 template <bool threads, int inst>
    582 typename __default_alloc_template<threads, inst>::obj * __VOLATILE
    583 __default_alloc_template<threads, inst>::free_list[
    584 # ifdef __SUNPRO_CC
    585     __NFREELISTS
    586 # else
    587     __default_alloc_template<threads, inst>::__NFREELISTS
    588 # endif
    589 ] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
    590 
    591 # ifdef __STL_WIN32THREADS
    592   // Create one to get critical section initialized.
    593   // We do this onece per file, but only the first constructor
    594   // does anything.
    595   static alloc __node_allocator_dummy_instance;
    596 # endif
    597 
    598 # endif /* ! __USE_MALLOC */
    599 
    600 #if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
    601 #pragma reset woff 1174
    602 #endif
    603 
    604 __STL_END_NAMESPACE
    605 
    606 #undef __PRIVATE
    607 
    608 #endif /* __SGI_STL_INTERNAL_ALLOC_WJZH_H */
    609 
    610 //End
    View Code

      

  • 相关阅读:
    caffe常用层: batchNorm层和scale层
    简述configure、pkg-config、pkg_config_path三者的关系
    python删除list中元素的三种方法
    Leetcode 872. Leaf-Similar Trees
    Leetcode 508. Most Frequent Subtree Sum
    Leetcode 572. Subtree of Another Tree
    Leetcode 894. All Possible Full Binary Trees
    Leetcode 814. Binary Tree Pruning
    Leetcode 557. Reverse Words in a String III
    python 多维list声明时的小问题
  • 原文地址:https://www.cnblogs.com/wangjzh/p/4097355.html
Copyright © 2011-2022 走看看