STL的第二级空间配置器代码分析[1]

2013年4月25日 由 Creater 留言 »

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);
  };
广告位

发表评论

你必须 登陆 方可发表评论.