Chinaunix首页 | 论坛 | 博客
  • 博客访问: 248499
  • 博文数量: 22
  • 博客积分: 1806
  • 博客等级: 上尉
  • 技术积分: 272
  • 用 户 组: 普通用户
  • 注册时间: 2006-11-16 20:10
文章分类

全部博文(22)

文章存档

2010年(6)

2009年(16)

分类: C/C++

2009-05-26 15:49:20

 

3620.            /* allocate a large request from the best fitting chunk in a treebin */

MAX_SMALL_REQUEST对齐值<= nb < MAX_REQUEST对齐值

3621.            static void* tmalloc_large(mstate m, size_t nb) {

3622.              tchunkptr v = 0;

设置初始值,注意rsizesize_t类型变量,因此一个很小的负数事实上是一个很大的正数。

3623.              size_t rsize = -nb; /* Unsigned negation */

3624.              tchunkptr t;

3625.              bindex_t idx;

计算nb字节数所对应的dltree树结构。

3626.              compute_tree_index(nb, idx);

3627.             

dltree树结构不为空,即存在和nb字节数同在一个箱子内(不理解“同在一个箱子内”则请查看前面讲解dltree内容部分)的空闲chunk块。

3628.              if ((t = *treebin_at(m, idx)) != 0) {

3629.                /* Traverse tree for this bin looking for node with size == nb */

遍历dltree试图找到一个size==nb的空闲chunk块。

前面曾经讲到过dltree就是关键码只有01Trie树。并且根据treebins箱的分法,0号箱和1号箱的关键码都只需7位长(因为其范围为128,表xxx的第二列),2号箱和3号箱的关键码都只需8位长(因为其范围为256,表xxx的第二列),……,依次类似。

leftshift_for_tree_index(idx)计算的是32 减去 idx号箱对应的关键码长度 的值。

#define leftshift_for_tree_index(i) \

   ((i == NTREEBINS-1)? 0 : \

    ((SIZE_T_BITSIZE-SIZE_T_ONE) - (((i) >> 1) + TREEBIN_SHIFT - 2)))

#define NTREEBINS         (32U)

#define SIZE_T_BITSIZE      (sizeof(size_t) << 3)

#define TREEBIN_SHIFT     (8U)

#define SIZE_T_ONE          ((size_t)1)

 

直接来看具体的值吧,依旧是32位平台下:

箱号idx => leftshift_for_tree_index(idx)

0=>25

1=>25

2=>24

3=>24

4=>23

5=>23

6=>22

7=>22

8=>21

9=>21

10=>20

11=>20

12=>19

13=>19

14=>18

15=>18

16=>17

17=>17

18=>16

19=>16

20=>15

21=>15

22=>14

23=>14

24=>13

25=>13

26=>12

27=>12

28=>11

29=>11

30=>10

31=>0

 

因此下面这个sizebits的值就是将nb中起关键码作用的位移到最左边的结果值。

3630.                size_t sizebits = nb << leftshift_for_tree_index(idx);

3631.                tchunkptr rst = 0;  /* The deepest untaken right subtree */

3632.                for (;;) {

3633.                  tchunkptr rt;

相差多大?

chunksize用于计算chunk块大小。

#define chunksize(p)        ((p)->head & ~(INUSE_BITS))

3634.                  size_t trem = chunksize(t) - nb;

比之前选定的chunk块更合适?

3635.                  if (trem < rsize) {

3636.                    v = t;

没有比它更合适的了,就是它了。

3637.                    if ((rsize = trem) == 0)

3638.                      break;

3639.                  }

记录当前节点的右子树根节点。

3640.                  rt = t->child[1];

根据关键码值进入相应的子树。

3641.                  t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];

rst保存包含有最接近nb字节数大小chunk块的dltree子树。

3642.                  if (rt != 0 && rt != t)

3643.                    rst = rt;

将要继续查找的子树为空,则保存rstt,然后跳出for循环。

3644.                  if (t == 0) {

3645.                    t = rst; /* set t to least subtree holding sizes > nb */

3646.                    break;

3647.                  }

3648.                  sizebits <<= 1;

3649.                }

3650.              }

3651.             

tv都为0表示请求字节大小对应的treebin为空,因此只有在更大的箱号内查找。

3652.              if (t == 0 && v == 0) { /* set t to root of next non-empty treebin */

和前面的某些代码类似,计算包含大于请求字节数目chunk块的所有箱号对应掩码。

3653.                binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap;

存在。

3654.                if (leftbits != 0) {

3655.                  bindex_t i;

选择最合适的分箱。

3656.                  binmap_t leastbit = least_bit(leftbits);

计算对应箱号。

3657.                  compute_bit2idx(leastbit, i);

箱子对应dltree根节点。

3658.                  t = *treebin_at(m, i);

3659.                }

3660.              }

3661.             

执行到这已经可以确定以t为根节点的dltree中所有chunk块都可满足申请请求,下面这个循环只不过试图在这个dltree中找到一个最合适的chunk块来用于内存分配。最合适的chunk块被保存在变量v内。

3662.              while (t != 0) { /* find smallest of tree or subtree */

3663.                size_t trem = chunksize(t) - nb;

3664.                if (trem < rsize) {

3665.                  rsize = trem;

3666.                  v = t;

3667.                }

leftmost_child宏优先选取左子树,在左子树为空的情况下则选取右子树。

#define leftmost_child(t) ((t)->child[0] != 0? (t)->child[0] : (t)->child[1])

3668.                t = leftmost_child(t);

3669.              }

3670.             

3671.              /*  If dv is a better fit, return 0 so malloc will use it */

前面在treebins中选择的chunk块存在(即变量v不为空),并且它比dv chunk块更适合(即选择的chunk块大小比dv chunk块大小更接近当前请求字节数目)用于内存分配以服务当前申请请求。如果dv chunk块更适合用来分配,则本函数将返回0,因此会在返回到dlmalloc函数内再进行在dv chunk块的内存分配操作。

3672.              if (v != 0 && rsize < (size_t)(m->dvsize - nb)) {

下面同样是分割、组建新chunk块、设置边界标记等,在此不再累述。

3673.                if (RTCHECK(ok_address(m, v))) { /* split */

3674.                  mchunkptr r = chunk_plus_offset(v, nb);

3675.                  assert(chunksize(v) == rsize + nb);

3676.                  if (RTCHECK(ok_next(v, r))) {

3677.                    unlink_large_chunk(m, v);

3678.                    if (rsize < MIN_CHUNK_SIZE)

3679.                      set_inuse_and_pinuse(m, v, (rsize + nb));

3680.                    else {

3681.                      set_size_and_pinuse_of_inuse_chunk(m, v, nb);

3682.                      set_size_and_pinuse_of_free_chunk(r, rsize);

3683.                      insert_chunk(m, r, rsize);

3684.                    }

3685.                    return chunk2mem(v);

3686.                  }

3687.                }

3688.                CORRUPTION_ERROR_ACTION(m);

3689.              }

3690.              return 0;

3691.            }

3692.             

 

 

3322.            /* Get memory from system using MORECORE or MMAP */

3323.            static void* sys_alloc(mstate m, size_t nb) {

3324.              char* tbase = CMFAIL;

3325.              size_t tsize = 0;

3326.              flag_t mmap_flag = 0;

3327.             

相关设置值的初始化。

3328.              init_mparams();

3329.             

3330.              /* Directly map large chunks */

dlmalloc向系统申请内存有两种方式:一为ORECORE(使用函数sbrk())方式;一为MMAP(使用函数mmap())方式。由于MMAP方式一般都是取到不连续的内存空间,因此只有在某些情况下(见下面)才使用它。

如果设置允许调用mmap函数并且字节数nb已超过了预设的可以调用mmap界限则利用mmap函数向系统申请内存。

3331.              if (use_mmap(m) && nb >= mparams.mmap_threshold) {

3332.                void* mem = mmap_alloc(m, nb);

3333.                if (mem != 0)

3334.                  return mem;

3335.              }

3336.             

根据相对优劣排序依次按照如下三种方法从系统获取内存:

1,利用MORECORE分配连续空间

2,利用MMAP分配新空间

3,利用MORECORE分配不连续空间

3337.              /*

3338.                Try getting memory in any of three ways (in most-preferred to

3339.                least-preferred order):

3340.                1. A call to MORECORE that can normally contiguously extend memory.

3341.                   (disabled if not MORECORE_CONTIGUOUS or not HAVE_MORECORE or

3342.                   or main space is mmapped or a previous contiguous call failed)

3343.                2. A call to MMAP new space (disabled if not HAVE_MMAP).

3344.                   Note that under the default settings, if MORECORE is unable to

3345.                   fulfill a request, and HAVE_MMAP is true, then mmap is

3346.                   used as a noncontiguous system allocator. This is a useful backup

3347.                   strategy for systems with holes in address spaces -- in this case

3348.                   sbrk cannot contiguously expand the heap, but mmap may be able to

3349.                   find space.

3350.                3. A call to MORECORE that cannot usually contiguously extend memory.

3351.                   (disabled if not HAVE_MORECORE)

3352.              */

3353.             

use_noncontiguous定义如下:

#define use_noncontiguous(M)  ((M)->mflags &   USE_NONCONTIGUOUS_BIT)

3354.              if (MORECORE_CONTIGUOUS && !use_noncontiguous(m)) {

试图利用MORECORE分配连续空间

3355.                char* br = CMFAIL;

函数segment_holding()用于查找某一内存地址所属于的segment段。具体代码如下,我们可以看到所谓的查找就是简单的线性扫描查找。

/* Return segment holding given address */

static msegmentptr segment_holding(mstate m, char* addr) {

  msegmentptr sp = &m->seg;

  for (;;) {

    if (addr >= sp->base && addr < sp->base + sp->size)

      return sp;

    if ((sp = sp->next) == 0)

      return 0;

  }

}

3356.                msegmentptr ss = (m->top == 0)? 0 : segment_holding(m, (char*)m->top);

3357.                size_t asize = 0;

上锁。

3358.                ACQUIRE_MORECORE_LOCK();

3359.             

top chunk块为空,即第一次分配情况。

3360.                if (ss == 0) {  /* First time through or recovery */

获取内存的当前边界点(即所谓的当前中断点)。CALL_MORECORE间接的调用sbrk()函数。函数sbrk()移动设置新的当前中断点并返回设置之前的中断点。

#define CALL_MORECORE(S)     MORECORE(S)

extern void*     sbrk(ptrdiff_t);

3361.                  char* base = (char*)CALL_MORECORE(0);

3362.                  if (base != CMFAIL) {

进行对齐处理,这里的对齐一般以一个内存页大小(32位平台下,大部分情况是4K)为基准,也可自由设置,比如64K

3363.                    asize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE);

3364.                    /* Adjust to end on a page boundary */

起始边界不是页对齐,则需要将末尾边界调整为页对齐。

#define is_page_aligned(S)\

   (((size_t)(S) & (mparams.page_size - SIZE_T_ONE)) == 0)

#define page_align(S)\

 (((S) + (mparams.page_size)) & ~(mparams.page_size - SIZE_T_ONE))

3365.                    if (!is_page_aligned(base))

3366.                      asize += (page_align((size_t)base) - (size_t)base);

3367.                    /* Can't call MORECORE if size is negative when treated as signed */

asize需要小于HALF_MAX_SIZE_Tsbrk()函数的参数是有符号的,如果大于HALF_MAX_SIZE_T,则传到sbrk()函数内部则成了负数。

#define HALF_MAX_SIZE_T     (MAX_SIZE_T / 2U)

#define MAX_SIZE_T           (~(size_t)0)

3368.                    if (asize < HALF_MAX_SIZE_T &&

3369.                        (br = (char*)(CALL_MORECORE(asize))) == base) {

利用MORECORE分配连续空间成功。

3370.                      tbase = base;

3371.                      tsize = asize;

3372.                    }

3373.                  }

3374.                }

3375.                else {

top chunk块存在的情况。

3376.                  /* Subtract out existing available top space from MORECORE request. */

3377.                  asize = granularity_align(nb - m->topsize + TOP_FOOT_SIZE + SIZE_T_ONE);

3378.                  /* Use mem here only if it did continuously extend old space */

3379.                  if (asize < HALF_MAX_SIZE_T &&

3380.                      (br = (char*)(CALL_MORECORE(asize))) == ss->base+ss->size) {

3381.                    tbase = br;

3382.                    tsize = asize;

3383.                  }

3384.                }

3385.             

部分操作失败的处理。

3386.                if (tbase == CMFAIL) {    /* Cope with partial failure */

3387.                  if (br != CMFAIL) {    /* Try to use/extend the space we did get */

3388.                    if (asize < HALF_MAX_SIZE_T &&

3389.                        asize < nb + TOP_FOOT_SIZE + SIZE_T_ONE) {

3390.                      size_t esize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE - asize);

3391.                      if (esize < HALF_MAX_SIZE_T) {

3392.                        char* end = (char*)CALL_MORECORE(esize);

3393.                        if (end != CMFAIL)

3394.                          asize += esize;

3395.                        else {            /* Can't use; try to release */

3396.                          CALL_MORECORE(-asize);

3397.                          br = CMFAIL;

3398.                        }

3399.                      }

3400.                    }

3401.                  }

3402.                  if (br != CMFAIL) {    /* Use the space we did get */

3403.                    tbase = br;

3404.                    tsize = asize;

3405.                  }

如果本次试图申请连续内存空间失败,则再次申请内存时候就直接放弃这种尝试。

#define disable_contiguous(M) ((M)->mflags |=  USE_NONCONTIGUOUS_BIT)

3406.                  else

3407.                    disable_contiguous(m); /* Don't try contiguous path in the future */

3408.                }

3409.             

解锁。

3410.               RELEASE_MORECORE_LOCK();

3411.              }

3412.             

尝试利用mmap申请内存空间。

3413.              if (HAVE_MMAP && tbase == CMFAIL) {  /* Try MMAP */

3414.                size_t req = nb + TOP_FOOT_SIZE + SIZE_T_ONE;

3415.                size_t rsize = granularity_align(req);

3416.                if (rsize > nb) { /* Fail if wraps around zero */

CALL_MMAP宏定义:

#define CALL_MMAP(s)         mmap(0, (s), MMAP_PROT, MMAP_FLAGS, -1, 0)

3417.                  char* mp = (char*)(CALL_MMAP(rsize));

3418.                  if (mp != CMFAIL) {

3419.                    tbase = mp;

3420.                    tsize = rsize;

3421.                    mmap_flag = IS_MMAPPED_BIT;

3422.                  }

3423.                }

3424.              }

3425.             

尝试利用MORECORE申请不连续内存空间。

3426.              if (HAVE_MORECORE && tbase == CMFAIL) { /* Try noncontiguous MORECORE */

3427.                size_t asize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE);

3428.                if (asize < HALF_MAX_SIZE_T) {

3429.                  char* br = CMFAIL;

3430.                  char* end = CMFAIL;

3431.                  ACQUIRE_MORECORE_LOCK();

3432.                  br = (char*)(CALL_MORECORE(asize));

3433.                  end = (char*)(CALL_MORECORE(0));

3434.                  RELEASE_MORECORE_LOCK();

3435.                  if (br != CMFAIL && end != CMFAIL && br < end) {

3436.                    size_t ssize = end - br;

3437.                    if (ssize > nb + TOP_FOOT_SIZE) {

3438.                      tbase = br;

3439.                      tsize = ssize;

3440.                    }

3441.                  }

3442.                }

3443.              }

3444.             

对新分配内存进行处理,牵扯到的变量比较多,处理也比较繁琐,但是都比较简单,因此也没有什么特别好讲解的,在此略过。

3445.              if (tbase != CMFAIL) {

3446.             

3447.                if ((m->footprint += tsize) > m->max_footprint)

3448.                  m->max_footprint = m->footprint;

3449.             

3450.                if (!is_initialized(m)) { /* first-time initialization */

3451.                  m->seg.base = m->least_addr = tbase;

3452.                  m->seg.size = tsize;

3453.                  m->seg.sflags = mmap_flag;

3454.                  m->magic = mparams.magic;

3455.                  init_bins(m);

3456.                  if (is_global(m))

3457.                    init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE);

3458.                  else {

3459.                    /* Offset top by embedded malloc_state */

3460.                    mchunkptr mn = next_chunk(mem2chunk(m));

3461.                    init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) -TOP_FOOT_SIZE);

3462.                  }

3463.                }

3464.             

3465.                else {

3466.                  /* Try to merge with an existing segment */

3467.                  msegmentptr sp = &m->seg;

3468.                  while (sp != 0 && tbase != sp->base + sp->size)

3469.                    sp = sp->next;

3470.                  if (sp != 0 &&

3471.                      !is_extern_segment(sp) &&

3472.                      (sp->sflags & IS_MMAPPED_BIT) == mmap_flag &&

3473.                      segment_holds(sp, m->top)) { /* append */

3474.                    sp->size += tsize;

3475.                    init_top(m, m->top, m->topsize + tsize);

3476.                  }

3477.                  else {

3478.                    if (tbase < m->least_addr)

3479.                      m->least_addr = tbase;

3480.                    sp = &m->seg;

3481.                    while (sp != 0 && sp->base != tbase + tsize)

3482.                      sp = sp->next;

3483.                    if (sp != 0 &&

3484.                        !is_extern_segment(sp) &&

3485.                        (sp->sflags & IS_MMAPPED_BIT) == mmap_flag) {

3486.                      char* oldbase = sp->base;

3487.                      sp->base = tbase;

3488.                      sp->size += tsize;

3489.                      return prepend_alloc(m, tbase, oldbase, nb);

3490.                    }

3491.                    else

3492.                      add_segment(m, tbase, tsize, mmap_flag);

3493.                  }

3494.                }

3495.             

3496.                if (nb < m->topsize) { /* Allocate from new or extended top space */

3497.                  size_t rsize = m->topsize -= nb;

3498.                  mchunkptr p = m->top;

3499.                  mchunkptr r = m->top = chunk_plus_offset(p, nb);

3500.                  r->head = rsize | PINUSE_BIT;

3501.                  set_size_and_pinuse_of_inuse_chunk(m, p, nb);

3502.                  check_top_chunk(m, m->top);

3503.                  check_malloced_chunk(m, chunk2mem(p), nb);

3504.                  return chunk2mem(p);

3505.                }

3506.              }

3507.             

3508.              MALLOC_FAILURE_ACTION;

3509.              return 0;

3510.            }

 

阅读(4352) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~