Solaris Slab Allocator–Magazines[3]

Object Construction

经典的slab allocator在slab创建的时候给slab中的每个object应用constructor。这样当从slab中申请object的时候,拿到的object都是初始化好的。但是我们看这样一个极端的情况:假设每个object是8个字节大小,如果一个slab含有一个8K的页面,那一个slab可以容纳1024个object,如果该object的构造函数中为每个object申请1K 内存,那当这个 slab创建的时候一共分配了1M的内存。但是如果这个slab中只有很少的一部分object被实际使用,那很多的内存就被浪费了!

当引入magazine之后,solaris的策略是:

  1. slab中维护raw buffer,将object construction操作从slab layer上升到magazine layer中进行。
  2. 在 buffer 进入到magazine layer的时候进行construction。
  3. 当object 从magazine 还回slab layer时进行destruction,从而变成raw buffer。

不能迷信别人说的话,我们来看看实际的代码:umem_cache_alloc

    //情况4:从magazine layer分配full magazine失败, 我们试图slab layer取一块raw buffer
 
      buf = umem_slab_alloc(cp, umflag); //注意,返回的buffer是没有应用过构造函数的
        …
      if (cp->cache_flags & UMF_BUFTAG) {
          
           //Let umem_cache_alloc_debug() apply the constructor for us.
           if (umem_cache_alloc_debug(cp, buf, umflag) == -1) {
                if (umem_alloc_retry(cp, umflag)) {
                   goto retry;
                }
                return (NULL);
            }
            return (buf);  //一切顺利的话,返回构造好的object。
       }

注意到在umem_cache_alloc的情况4中并没有分配full magazine的代码哦!那full magazine是怎么产生的呢?首先我们要区分两个概念:

  1. Object Allocation: 在分配时,如果depot layer没有full magazine了,我们直接从slab layer取并应用constructor.
  2. Magazine Allocation: 在释放时,如果depot没有empty magazine,我们分配一个magazine。

Magazine只是一个管理容器。我们从不显式的分配full magazine,因为这没有必要 。当application释放objects的时候,就会将empty magazine填充成full magazine。

来看一下umem_cache_free 的代码:

_umem_cache_free(umem_cache_t *cp, void *buf)
{
      …
      for(;;){
               //情况1:当前magazine不是full magazine ,直接把object归还
               //情况2:当前magazine是full但是previous magazine为空,交换cur和prev后重试
               //情况3:cur和prev magazine都是full,从depot上取一个empty magazine…
               …
               //情况4:  1,2,3都失败了以后,试图分配empty magazine
               umem_magazine_t *emp = _umem_cache_alloc(mtp->mt_cache,UMEM_DEFAULT);
               if(emp!=NULL)
               {
                      umem_depot_free(cp, &cp->cache_empty,emp); //将分配的 empty magazine加到depot中
                      continue; //重试,于是下一轮会落入情况3
                }
                break; //如果分配empty magazine都失败了,我们只好调用slab_free直接返回给slab了。
         }
         umem_slab_free(cp,buf);
}

对于为什么从不显式分配full magazine我不是非常理解。我的猜测是:magazine其实是个容器,所谓full magazine,不过是先分配empty magazine,然后预先填充M个objects。如果 magazine的rounds=M,相当于要事先调用M次constructor,而其中M-1次都是负担。但是如果没有分配full magazine,就会使得cache miss rate上升啊??希望有同学可以解答我的疑问-:)    

你可能感兴趣的:(object,cache,Solaris,Constructor,Allocation,construction)