• 欢迎浏览“String me = Creater\忠实的资深Linux玩家;”,请文明浏览,理性发言,有侵犯你的权益请邮件我(creater@vip.qq.com).
  • 把任何的失败都当作一次尝试,不要自卑;把所有的成功都想成是一种幸运,不要自傲。
  •    5年前 (2013-04-25)  STL |   3 条评论  20 
    文章评分 0 次,平均分 0.0

    STL的第二级空间配置器里有很多经典的思想,确实值得细细品味。
    为什么使用如下的代码:

      static size_t ROUND_UP(size_t bytes) {
            return (((bytes) + __ALIGN-1) & ~(__ALIGN - 1));
      }

    他的原理可以看这里


    再看下面的代码

      union obj {
            union obj * free_list_link;
            char client_data[1];    /* The client sees this.        */
      };

    原理是:
    union结构里的第一个成员free_list_link,是指向下一个小额区块的指针。第二个成员client_data是用户来访问小额区块内的数据的。
    那么,为什么要用union结构呢?
    这是为了节省空间。我们知道,union中的结构成员共享同一块内存,在同一时刻只能访问一个成员。这样就节省了内存空间。当节点所代表的内存块是内存池中的空闲块时,这时候union结构存储的是free_list_link;但是当节点代表的内存块已分配给用户时,存储的是client_data,供用户访问使用。

    再看

      static void *refill(size_t n);
      // Allocates a chunk for nobjs of size "size".  nobjs may be reduced
      // if it is inconvenient to allocate the requested number.
    	// 返回nobjs个size大小的内存块,实际申请的size大小的个数靠nobjs这个值-结果参数返回
      static char *chunk_alloc(size_t size, int &nobjs);
      // Chunk allocation state.
      static char *start_free;
      static char *end_free;
      static size_t heap_size;

    start_free代表内存池的起始位置;
    end_free代表内存池的结束位置;
    refill用来分配一个大小为n的内存块;
    chunk_alloc用来分配nobjs个大小为size的内存块,并且分配的结果数由值-结果参数传出。

    再看

    static void * allocate(size_t n);
     static void deallocate(void *p, size_t n);
     static void * reallocate(void *p, size_t old_sz, size_t new_sz);
    

    这三个函数则是给于外部的接口,在simple-alloc包装下适应了标准。
    在allocate中使用了obj * __VOLATILE * my_free_list;
    这个的含义是:*my_free_list指向的内存不需要优化,每次读取都需要在实际的地址内读取。因为*my_free_list返回的就是可用的内存地址,可能会在多个线程或者频繁申请时发生变化,所以不需要优化。

    注释代码

    static void * allocate(size_t n)
      {
    	//用于存放自由链表某个节点的地址
        obj * __VOLATILE * my_free_list;
    		//实际分配的地址
        obj * __RESTRICT result;
    
    		//如果分配的内存太大,则需要交给第一级
        if (n > (size_t) __MAX_BYTES) {
            return(malloc_alloc::allocate(n));
        }
    		//确定16个自由链表中最合适的一个
        my_free_list = free_list + FREELIST_INDEX(n);
        // Acquire the lock here with a constructor call.
        // This ensures that it is released in exit or during stack
        // unwinding.
    #       ifndef _NOTHREADS
            /*REFERENCED*/
            lock lock_instance;
    #       endif
    	//得到自由链表指向的空闲区
        result = *my_free_list;
        if (result == 0) {
            void *r = refill(ROUND_UP(n));
            return r;
        }
    		//更改指针,分配一个区块出去
        *my_free_list = result -> free_list_link;
        return (result);
      };
    
     

    除特别注明外,本站所有文章均为String me = "Creater\忠实的资深Linux玩家";原创,转载请注明出处来自http://unix8.net/home.php/868.html

    关于

    发表评论

    暂无评论

    切换注册

    登录

    忘记密码 ?

    切换登录

    注册

    扫一扫二维码分享