dlmalloc-2.6.6源码分析(二)

3. 分箱管理

bin的英文含义是”箱柜“,当我们谈到bin,是指某个双向链表的头节点,该链表的成员节点存放着某一特定范围size的空闲chunk。通过size,我们可以快速的定位bin index,然后遍历其指向的链表,寻找合适的chunk进行分配,或者将释放的chunk插入到链表中合适的地方。

6

程序定义了一个全局静态数组av_[]存放每种bin的头节点,

typedef struct malloc_chunk* mbinptr;

static mbinptr av_[128 * 2 + 2]

数组类型mbinptr是一个指针,大小为4个字节,数组大小为(128×2+2)*4 = 1032字节,

这就引出一个问题,既然存放头节点,节点类型为malloc_chunk,一个节点就需要16 bytes,总共有128个头节点,理应需要128*16 = 2048字节才对,现在av_[ ]1032字节,是如何放下所有的头节点信息的呢?对于头节点而言,有效的是fdbk,成员prev_sizesize并没有用到,既然没用,那空间能否节约下来呢?可以的,看看dlmalloc是如何做到的。

#define bin_at(i)      ((mbinptr)((char*)&(av_[2*(i) + 2]) - 2*4))

以分配16 bytes为例,其箱号为 16 / 8 = 2,于是,bin_at(2)-->((mbinptr)((char*)&(av_[6]) - 2*4)),最终bin_at(2)将地址 &av_[4] 强行转换为mbinptr指针,用这个指针访问fdbk,得到的其实是av_[6]av_[7]中存放的内容。

我们看看dlmalloc中两个特殊的分箱toplast_remainder

#define top      (bin_at(0)->fd)       /* The topmost chunk */

#define last_remainder (bin_at(1))       /* remainder from last split */

top最初被称为wilderness chunk,指向dlmalloc可用内存的最高端的边界chunk,因为在边界处,top是唯一一个可以任意扩展的块(在Unix上可以通过库函数sbrk( ))。top比较特殊,它不受任何分箱管理,当其它分箱没有可用的chunk时才会用到top。在dlmalloc初始化刚完成时,整个受dlmalloc管理的内存就是一个chunktop即指向这个chunk

last_remainder总是指向最近被分割chunk的剩下那一部分。如果malloc( )在分配时没找到“精确匹配”的块,则优先去查看last_remainder是否够用。从局部性原理来讲,连续申请分配内存的代码总是趋向于有共同的生命周期,它们释放的chunk也就有更大的机会合并成一个大的chunk

 

了解完toplast_remainder,我们继续往下看。last_remainder的箱号为1bin_at(1)将地址 &av_[2] 强行转换为mbinptr指针,访问fdbk,得到的其实是av_[4]av_[5]中存放的内容,即bin_at(2)prev_size域和bin_at(1)fd域重叠,bin_at(2)size域和bin_at(1)bk域重叠,看起来像这样(方格内的数字以4个字节为单位)

7

同理,bin_at(1)prev_size域和bin_at(0)fd域重叠,bin_at(1)size域和bin_at(0)bk域重叠在一起。通过这种叠加使用,dlmalloc使得本该占据2048字节空间的需求变成了1032字节。这里体现了Doug Lea的一个设计宗旨:Minimizing Space,即用于heap控制的内存要最小化。原话是这样说的,

The allocator should not waste space: it should obtain as little memory from the system as possible, and shoud maintain memory in ways that minimize fragmentation--"holes" in contiguous chunks of memory that are not used by the program.

好吧,你说,必须得承认,dlmalloc确实很省空间,但是从上面这个图看来, av_[0]av_[1]似乎没有被用到,浪费好像不符合Minimizing Space的原则哦。

当然不会,dlmalloc为达到快速检索分箱的目的,使用了一个小技巧,

 #define binblocks      (bin_at(0)->size) /* bitvector of nonempty blocks */

即用binblocks建立了所有分箱的一个bitmapbinblocksbit来表示连续的4个相邻的bin是否为空,只要有一个不为空,其对应的bit1。 binblocks实际上是av_[1],一个32位数据类型,32×4=128,正好对应128bins。扫描时先判断binblocks的相应位,只有当bit不为空时才会真正的去扫描对应的bin

每一个bin的用途描述如下:

#define top      (bin_at(0)->fd)       /* The topmost chunk */

#define last_remainder (bin_at(1))       /* remainder from last split */

由上宏定义可知,

top(topmost chunk) --> 0

last_remainder    --> 1

对小于512 bytes的内存申请,箱号 = size / 8,分箱如下:

0x    0 ~ 0x  1ff --> 2 ~ 63;

大于等于512 bytes的分箱如下(以下数据用程序打印出来):

0x  200 ~ 0x  23f --> 64

0x  240 ~ 0x  27f --> 65

0x  280 ~ 0x  2bf --> 66

0x  2c0 ~ 0x  2ff --> 67

0x  300 ~ 0x  33f --> 68

0x  340 ~ 0x  37f --> 69

0x  380 ~ 0x  3bf --> 70

0x  3c0 ~ 0x  3ff --> 71

0x  400 ~ 0x  43f --> 72

0x  440 ~ 0x  47f --> 73

0x  480 ~ 0x  4bf --> 74

0x  4c0 ~ 0x  4ff --> 75

0x  500 ~ 0x  53f --> 76

0x  540 ~ 0x  57f --> 77

0x  580 ~ 0x  5bf --> 78

0x  5c0 ~ 0x  5ff --> 79

0x  600 ~ 0x  63f --> 80

0x  640 ~ 0x  67f --> 81

0x  680 ~ 0x  6bf --> 82

0x  6c0 ~ 0x  6ff --> 83

0x  700 ~ 0x  73f --> 84

0x  740 ~ 0x  77f --> 85

0x  780 ~ 0x  7bf --> 86

0x  7c0 ~ 0x  7ff --> 87

0x  800 ~ 0x  83f --> 88

0x  840 ~ 0x  87f --> 89

0x  880 ~ 0x  8bf --> 90

0x  8c0 ~ 0x  8ff --> 91

0x  900 ~ 0x  93f --> 92

0x  940 ~ 0x  97f --> 93

0x  980 ~ 0x  9bf --> 94

0x  9c0 ~ 0x  9ff --> 95

0x  a00 ~ 0x  bff --> 96

0x  c00 ~ 0x  dff --> 97

0x  e00 ~ 0x  fff --> 98

0x 1000 ~ 0x 11ff --> 99

0x 1200 ~ 0x 13ff --> 100

0x 1400 ~ 0x 15ff --> 101

0x 1600 ~ 0x 17ff --> 102

0x 1800 ~ 0x 19ff --> 103

0x 1a00 ~ 0x 1bff --> 104

0x 1c00 ~ 0x 1dff --> 105

0x 1e00 ~ 0x 1fff --> 106

0x 2000 ~ 0x 21ff --> 107

0x 2200 ~ 0x 23ff --> 108

0x 2400 ~ 0x 25ff --> 109

0x 2600 ~ 0x 27ff --> 110

0x 2800 ~ 0x 29ff --> 111

0x 2a00 ~ 0x 2fff --> 112

0x 3000 ~ 0x 3fff --> 113

0x 4000 ~ 0x 4fff --> 114

0x 5000 ~ 0x 5fff --> 115

0x 6000 ~ 0x 6fff --> 116

0x 7000 ~ 0x 7fff --> 117

0x 8000 ~ 0x 8fff --> 118

0x 9000 ~ 0x 9fff --> 119

0x a000 ~ 0x ffff --> 120

0x10000 ~ 0x17fff --> 121

0x18000 ~ 0x1ffff --> 122

0x20000 ~ 0x27fff --> 123

0x28000 ~ 0x3ffff --> 124

0x40000 ~ 0x7ffff --> 125

  size >= 0x80000 --> 126

dlmalloc的实现使用两个宏来完成对于bin链表的插入和删除操作。宏定义frontlink(P, S, IDX, BK, FD)将某个chunk放入对应的bin链表,定义如下:

#define frontlink(P, S, IDX, BK, FD) \

{ \

  if (S<MAX_SMALLBIN_SIZE) \

  { \

    IDX = smallbin_index(S); \

    mark_binblock(IDX); \

    BK = bin_at(IDX); \

    FD = BK->fd; \

    P->bk = BK; \

    P->fd = FD; \

    FD->bk = BK->fd = P; \

  } \

  else \

  { \

    IDX = bin_index(S); \

    BK = bin_at(IDX); \

    FD = BK->fd; \

    if (FD == BK) mark_binblock(IDX); \

    else \

    { \

      while (FD != BK && S < chunksize(FD)) FD = FD->fd; \

      BK = FD->bk; \

    } \

    P->bk = BK; \

    P->fd = FD; \

    FD->bk = BK->fd = P; \

  } \

}

对应的逻辑示意图如下:

8

如果chunk size小于512,则很好挂载,先除以8找到箱号,然后插入到头节点和头节点fd域指向的第一个节点之间,因为所有的chunk大小都一样;

如果chunk size大于等于512,则稍微麻烦一点,沿着头节点fd指针开始寻找,或者碰到size相等或更大的chunk,则插在该chunk之前;如果需挂载chunksize

在该bin中最大,则插在最后一个chunk和头节点之间。这种最糟糕的情况会导致遍历完整个链表才能找到插入的地方,从执行效率来讲,并非最佳。在dlmalloc 2.8.3版本中,这一部分不再使用双向链表,而是使用二叉树来管理,在搜素上会更快速。                    

                      

宏定义unlink(P, BK, FD)则将一个chunk从它所在的链表取走,类似于将一个节点从双向链表中解除。其定义如下:                      

                      

/* take a chunk off a list */

#define unlink(P, BK, FD) \

{ \

  BK = P->bk; \

  FD = P->fd; \

  FD->bk = BK; \

  BK->fd = FD; \

}  



4. 内存分配相关函数

本节主要对dlmalloc内存分配器的核心函数mALLOc()以及相关函数进行讲解,函数mALLOc用于服务应用程序的内存空间申请请求,因此也是我们平常使用得最多的两个函数(另外一个fREe())之一。下面我们先来直接看源码并同时进行分析。(下面给出的源码都已标号,标号为源文件malloc-2.6.6.c内的实际行号,未标号的行都为我给出的分析注解内容。)

4.1函数mALLOc( )

2110  #if __STD_C

2111  Void_t* mALLOc(size_t bytes)

2112  #else

2113  Void_t* mALLOc(bytes) size_t bytes;

2114  #endif

2115  {

2116    mchunkptr victim;                  /* inspected/selected chunk */

2117    INTERNAL_SIZE_T victim_size;       /* its size */

2118    int       idx;                     /* index for bin traversal */

2119    mbinptr   bin;                     /* associated bin */

2120    mchunkptr remainder;               /* remainder from a split */

2121    long      remainder_size;          /* its size */

2122    int       remainder_index;         /* its bin index */

2123    unsigned long block;               /* block traverser bit */

2124    int       startidx;                /* first bin of a traversed block */

2125    mchunkptr fwd;                     /* misc temp for linking */

2126    mchunkptr bck;                     /* misc temp for linking */

2127    mbinptr q;                         /* misc temp */

2128  

2129    INTERNAL_SIZE_T nb;

2130  

2131    if ((long)bytes < 0) return 0;

2132  

          /*用户申请的size首先被转成系统可用的大小-->nb,即增加了4个字节,或者更 多(以满足8字节对齐的需         求),最终nb >= 16字节(系统最小的可分配size*/

2133    nb = request2size(bytes);  /* padded request size; */

2134  

2135    /* Check for exact match in a bin */

2136  

 /*找到nb对应的bin,扫描,如果找到一个精确的块,则分配。所谓精确 是指误差在16个字节内。*/

2137    if (is_small_request(nb))  /* Faster version for small requests */

2138    {

2139      idx = smallbin_index(nb); 

2140  

2141      /* No traversal or size check necessary for small bins.  */

2142  

2143      q = bin_at(idx);

2144      victim = last(q);

2145  

2146      /* Also scan the next one, since it would have a remainder < MINSIZE */

  /*如果nb对应的bin没有空闲块,则扫描下一个bin,对于smallbin而言,相邻   两个binsize仅相差8个字节,无需为剩下的8个字节重新建立一个空闲块,   从之前的叙述我们得知,可分配的空闲块>=16字节*/

2147      if (victim == q)

2148      {

2149        q = next_bin(q);

2150        victim = last(q);

2151      }

2152      if (victim != q)

2153      {

2154        victim_size = chunksize(victim);

2155        unlink(victim, bck, fwd);

2156        set_inuse_bit_at_offset(victim, victim_size);

2157        check_malloced_chunk(victim, nb);

2158        return chunk2mem(victim);

2159      }

2160  

2161      idx += 2; /* Set for bin scan below. We've already scanned 2 bins. */

2162  

2163    }

2164    else

2165    {

2166      idx = bin_index(nb);

2167      bin = bin_at(idx);

2168  

2169      for (victim = last(bin); victim != bin; victim = victim->bk)

2170      {

2171        victim_size = chunksize(victim);

2172        remainder_size = victim_size - nb;

2173        

2174        if (remainder_size >= (long)MINSIZE) /* too big */

2175        {

2176          --idx; /* adjust to rescan below after checking last remainder */

2177          break;   

2178        }

2179  

/*命中“精确”的空闲块,则从所在bin双向链表中移除,设置PREV_INUSE 标志,返回用户指针*/

2180        else if (remainder_size >= 0) /* exact fit */

2181        {

2182          unlink(victim, bck, fwd);

2183          set_inuse_bit_at_offset(victim, victim_size);

2184          check_malloced_chunk(victim, nb);

2185          return chunk2mem(victim);

2186        }

2187      }

2188  

2189      ++idx; 

2190  

2191    }

2192  

2193    /* Try to use the last split-off remainder */

2194  

/*如果精确chunk没有找到,而且last_remainder足够大,则在last remainder 中使用首次适应算法,该算法能让那些连续的chunk有相同或近似的生命周期,从 长期来看,有助于提升局部性和减少碎片。 */

2195    if ( (victim = last_remainder->fd) != last_remainder)

2196    {

2197      victim_size = chunksize(victim);

2198      remainder_size = victim_size - nb;

2199  

  /*如果last_remaindernb大,且差值大于等于16个字节,则把剩下的部分重   新挂到last_remainder*/

2200      if (remainder_size >= (long)MINSIZE) /* re-split */

2201      {

2202        remainder = chunk_at_offset(victim, nb);

2203        set_head(victim, nb | PREV_INUSE);

2204        link_last_remainder(remainder);

2205        set_head(remainder, remainder_size | PREV_INUSE);

2206        set_foot(remainder, remainder_size);

2207        check_malloced_chunk(victim, nb);

2208        return chunk2mem(victim);

2209      }

2210  

  /*如果last_remaindernb大,且差值小于16个字节,则一股脑儿都分配出去;   如果last_remaindernb小,则有理由怀疑last_remainder也不能满足下一次内   存申请,所以把它挂到一般的bin分箱中去。

  不管是那种情况,都将last_remainder清空,让它指向自己。*/

2211      clear_last_remainder;

2212  

2213      if (remainder_size >= 0)  /* exhaust */

2214      {

2215        set_inuse_bit_at_offset(victim, victim_size);

2216        check_malloced_chunk(victim, nb);

2217        return chunk2mem(victim);

2218      }

2219  

2220      /* Else place in bin */

2221  

2222      frontlink(victim, victim_size, remainder_index, bck, fwd);

2223    }

2224  

2225    /* 

2226       If there are any possibly nonempty big-enough blocks, 

2227       search for best fitting chunk by scanning bins in blockwidth units.

2228    */

2229  

/*如果适合分配的chunk还没找到,则以升序方式扫描其它bins,这里最佳适应算 法被采用,即满足需求的最小chunk被选中,分配后将剩余部分放入last_remainder

为了加速扫描过程,Doug Lea使用了一个小技巧,

#define binblocks      (bin_at(0)->size) /* bitvector of nonempty blocks */

binblocksbit来表示连续的4个相邻的bin是否为空,只要有一个不为空,其 对应的bit1binblocks实际上是av_[1],一个32位数据类型,32×4=128,正好 对应128bins。扫描时先判断binblocks值,只有当相应bit不为空时才会真正 的去扫描对应的bin。 */

2230    if ( (block = idx2binblock(idx)) <= binblocks)  

2231    {

2232  

2233      /* Get to the first marked block */

2234  

  /*blockbinblock的某一个位,bit[n],其值为1的话表示第n*4n*4+1n*4+2   n*4+3bin分箱中至少有一个bin不为空,这意味着至少有一个chunk能满足   内存申请。在扣除申请的内存后剩余的部分如果小于16个字节,则把这个      chunk全部分配给用户,如果剩余部分大于等于16个字节,则将剩余部分挂载   到last_remainder*/

2235      if ( (block & binblocks) == 0) 

2236      {

2237        /* force to an even block boundary */

2238        idx = (idx & ~(BINBLOCKWIDTH - 1)) + BINBLOCKWIDTH;

2239        block <<= 1;

2240        while ((block & binblocks) == 0)

2241        {

2242          idx += BINBLOCKWIDTH;

2243          block <<= 1;

2244        }

2245      }

2246        

2247      /* For each possibly nonempty block ... */

2248      for (;;)  

2249      {

2250        startidx = idx;          /* (track incomplete blocks) */

2251        q = bin = bin_at(idx);

2252  

2253        /* For each bin in this block ... */

2254        do

2255        {

2256          /* Find and use first big enough chunk ... */

2257  

2258          for (victim = last(bin); victim != bin; victim = victim->bk)

2259          {

2260            victim_size = chunksize(victim);

2261            remainder_size = victim_size - nb;

2262  

2263            if (remainder_size >= (long)MINSIZE) /* split */

2264            {

2265              remainder = chunk_at_offset(victim, nb);

2266              set_head(victim, nb | PREV_INUSE);

2267              unlink(victim, bck, fwd);

2268              link_last_remainder(remainder);

2269              set_head(remainder, remainder_size | PREV_INUSE);

2270              set_foot(remainder, remainder_size);

2271              check_malloced_chunk(victim, nb);

2272              return chunk2mem(victim);

2273            }

2274  

2275            else if (remainder_size >= 0)  /* take */

2276            {

2277              set_inuse_bit_at_offset(victim, victim_size);

2278              unlink(victim, bck, fwd);

2279              check_malloced_chunk(victim, nb);

2280              return chunk2mem(victim);

2281            }

2282  

2283          }

2284  

2285         bin = next_bin(bin);

2286  

2287        } while ((++idx & (BINBLOCKWIDTH - 1)) != 0);

2288  

2289        /* Clear out the block bit. */

2290  

2291        do   /* Possibly backtrack to try to clear a partial block */

2292        {

2293          if ((startidx & (BINBLOCKWIDTH - 1)) == 0)

2294          {

2295            binblocks &= ~block;

2296            break;

2297          }

2298          --startidx;

2299         q = prev_bin(q);

2300        } while (first(q) == q);

2301  

2302        /* Get to the next possibly nonempty block */

2303  

2304        if ( (block <<= 1) <= binblocks && (block != 0) ) 

2305        {

2306          while ((block & binblocks) == 0)

2307          {

2308            idx += BINBLOCKWIDTH;

2309            block <<= 1;

2310          }

2311        }

2312        else

2313          break;

2314      }

2315    }

2316  

2317  

2318    /* Try to use top chunk */

2319  

/*如果还没有找到适合分配的chunk,就去分割top chunk。由于top可以将memory 扩展到系统允许的上限,所以top会被认为比系统内可用的chunk都要大。*/

2320    /* Require that there be a remainder, ensuring top always exists  */

2321    if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE)

2322    {

2323  

2324  #if HAVE_MMAP

2325      /* If big and would otherwise need to extend, try to use mmap instead */

2326      if ((unsigned long)nb >= (unsigned long)mmap_threshold &&

2327          (victim = mmap_chunk(nb)) != 0)

2328        return chunk2mem(victim);

2329  #endif

2330  

2331      /* Try to extend */

2332      malloc_extend_top(nb);

2333      if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE)

2334        return 0; /* propagate failure */

2335    }

2336  

2337    victim = top;

2338    set_head(victim, nb | PREV_INUSE);

2339    top = chunk_at_offset(victim, nb);

2340    set_head(top, remainder_size | PREV_INUSE);

2341    check_malloced_chunk(victim, nb);

2342    return chunk2mem(victim);

2343  

2344  }

4.2函数malloc_update_mallinfo( )

在使用heap分配内存时,我们往往会关注整个heap的状况,比如heap的大小,内存分配掉多少,还剩多少等。数据结构体mallinfo即是为此目的而定义,如下:

struct mallinfo {

  int arena;    /* total space allocated from system—从系统分给heap使用的内存大小 */

  int ordblks;  /* number of non-inuse chunks—未使用的chunk个数 */

  int smblks;   /* unused -- always zero */

  int hblks;    /* number of mmapped regions */

  int hblkhd;   /* total space in mmapped regions —通过mmap( )分配的所有内存的大小*/

  int usmblks;  /* unused -- always zero */

  int fsmblks;  /* unused -- always zero */

  int uordblks; /* total allocated space —被分配使用的chunk个数*/

  int fordblks; /* total non-inuse space—未被分配使用的chunk个数*/

  int keepcost; /* top-most, releasable (via malloc_trim) space */

};

3047  static void malloc_update_mallinfo() 

3048  {

3049    int i;

3050    mbinptr b;

3051    mchunkptr p;

3052  #if DEBUG

3053    mchunkptr q;

3054  #endif

3055  

3056    INTERNAL_SIZE_T avail = chunksize(top);

3057    int   navail = ((long)(avail) >= (long)MINSIZE)? 1 : 0;

3058  

/*遍历所有分箱的双向链表,统计空闲块个数和总的size,并据此算出其它信息*/

3059    for (i = 1; i < NAV; ++i)

3060    {

3061      b = bin_at(i);

3062      for (p = last(b); p != b; p = p->bk) 

3063      {

3064  #if DEBUG

3065        check_free_chunk(p);

3066        for (q = next_chunk(p); 

3067             q < top && inuse(q) && (long)(chunksize(q)) >= (long)MINSIZE; 

3068             q = next_chunk(q))

3069          check_inuse_chunk(q);

3070  #endif

3071        avail += chunksize(p);

3072        navail++;

3073      }

3074    }

3075  

3076    current_mallinfo.ordblks = navail;

3077    current_mallinfo.uordblks = sbrked_mem - avail;

3078    current_mallinfo.fordblks = avail;

3079    current_mallinfo.hblks = n_mmaps;

3080    current_mallinfo.hblkhd = mmapped_mem;

3081    current_mallinfo.keepcost = chunksize(top);

3082  

3083  }

5. 内存回收相关函数

5.1函数fREe( )

2371  #if __STD_C

2372  void fREe(Void_t* mem)

2373  #else

2374  void fREe(mem) Void_t* mem;

2375  #endif

2376  {

2377    mchunkptr p;         /* chunk corresponding to mem */

2378    INTERNAL_SIZE_T hd;  /* its head field */

2379    INTERNAL_SIZE_T sz;  /* its size */

2380    int       idx;       /* its bin index */

2381    mchunkptr next;      /* next contiguous chunk */

2382    INTERNAL_SIZE_T nextsz; /* its size */

2383    INTERNAL_SIZE_T prevsz; /* size of previous contiguous chunk */

2384    mchunkptr bck;       /* misc temp for linking */

2385    mchunkptr fwd;       /* misc temp for linking */

2386    int       islr;      /* track whether merging with last_remainder */

2387  

2388    if (mem == 0)                              /* free(0) has no effect */

2389      return;

2390  

2391    p = mem2chunk(mem);

2392    hd = p->size;

2393  

2394  #if HAVE_MMAP

2395    if (hd & IS_MMAPPED)                       /* release mmapped memory. */

2396    {

2397      munmap_chunk(p);

2398      return;

2399    }

2400  #endif

2401    

2402    check_inuse_chunk(p);

2403    

2404    sz = hd & ~PREV_INUSE;

2405    next = chunk_at_offset(p, sz);

2406    nextsz = chunksize(next);

2407  

/*如果等待释放的chunkmemory的高端相邻,则被合并入top chunk*/  

2408    if (next == top)                            /* merge with top */

2409    {

2410      sz += nextsz;

2411  

/*查看前一个chunk是否为空闲,若是,则从所在的分箱双向链表中移除*/

2412      if (!(hd & PREV_INUSE))                    /* consolidate backward */

2413      {

2414        prevsz = p->prev_size;

2415        p = chunk_at_offset(p, -((long) prevsz));

2416        sz += prevsz;

2417        unlink(p, bck, fwd);

2418      }

2419  

  /*设置合并后chunksize,包含PREV_INUSE,因为此时其前一个chunk必定 被分配使用了;

重新设置top

若使用的memory超出了trim的界限,则调用malloc_trim()*/

2420      set_head(p, sz | PREV_INUSE);

2421      top = p;

2422      if ((unsigned long)(sz) >= (unsigned long)trim_threshold) 

2423        malloc_trim(top_pad); 

2424      return;

2425    }

2426  

/*清除下一个chunksize域的PREV_INUSE标志,表示当前chunk出于空闲*/

2427    set_head(next, nextsz);                    /* clear inuse bit */

2428  

2429    islr = 0;

2430  

/*被释放的chunk没有紧挨top*/

/*如果前一个chunk空闲,且其前指chunk不是last_remainder 则将前一个chunk 从所在分箱双向链表移除,否则只是置islr1,后续仅需更新p所指chunksize 即可*/

2431    if (!(hd & PREV_INUSE))                    /* consolidate backward */

2432    {

2433      prevsz = p->prev_size;

2434      p = chunk_at_offset(p, -((long) prevsz));

2435      sz += prevsz;

2436      

2437      if (p->fd == last_remainder)             /* keep as last_remainder */

2438        islr = 1;

2439      else

2440        unlink(p, bck, fwd);

2441    }

2442    

/*下一个chunk空闲,且其前指chunklast_remainder,则重新建立合并后的 chunk last_remainder之间的联系,否则只是将下一个chunk从所在分箱双向链表移除*/

2443    if (!(inuse_bit_at_offset(next, nextsz)))   /* consolidate forward */

2444    {

2445      sz += nextsz;

2446      

2447      if (!islr && next->fd == last_remainder)  /* re-insert last_remainder */

2448      {

2449        islr = 1;

2450        link_last_remainder(p);   

2451      }

2452      else

2453        unlink(next, bck, fwd);

2454    }

2455  

2456  

/*设置合并后chunksize,包含PREV_INUSE,因为此时其前一个chunk必定被 分配使用了;

设置下一个chunkprev_size,下一个chunk也必定被分配使用了,当下一个

chunk被释放时,可根据prev_size找到前一个chunk合并;

如果islr0,则说明当前chunklast_remainder没什么关系,需要将当前chunk 重新放入合适的分箱上向链表中*/

2457    set_head(p, sz | PREV_INUSE);

2458    set_foot(p, sz);

2459    if (!islr)

2460      frontlink(p, sz, idx, bck, fwd);  

2461  }


posted on 2010-06-08 07:57 yangfan 阅读(3040) 评论(1)  编辑 收藏 引用

评论

# re: dlmalloc-2.6.6源码分析(二) 2014-03-07 18:36 xmw

图8 中离表头近的size比较大吧

  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理


<2014年3月>
2324252627281
2345678
9101112131415
16171819202122
23242526272829
303112345

导航

统计

常用链接

留言簿

随笔档案

文章分类

文章档案

搜索

最新评论