dlmalloc(三)

有了上篇文章的基础,现在可以详细分析malloc()申请内存的流程了,代码如下:

void* dlmalloc(size_t bytes) {
  /*
     Basic algorithm:   算法描述
     If a small request (< 256 bytes minus per-chunk overhead):
       1. If one exists, use a remainderless chunk in associated smallbin.
          (Remainderless means that there are too few excess bytes to
          represent as a chunk.)
       2. If it is big enough, use the dv chunk, which is normally the
          chunk adjacent to the one used for the most recent small request.
       3. If one exists, split the smallest available chunk in a bin,
          saving remainder in dv.
       4. If it is big enough, use the top chunk.
       5. If available, get memory from system and use it
     Otherwise, for a large request:
       1. Find the smallest available binned chunk that fits, and use it
          if it is better fitting than dv chunk, splitting if necessary.
       2. If better fitting than any binned chunk, use the dv chunk.
       3. If it is big enough, use the top chunk.
       4. If request size >= mmap threshold, try to directly mmap this chunk.
       5. If available, get memory from system and use it

     The ugly goto's here ensure that postaction occurs along all paths.
  */

  if (!PREACTION(gm)) {
    void* mem;
    size_t nb;
    // 如果申请的内存量小于244字节,表示是小块内存.
    if (bytes <= MAX_SMALL_REQUEST) {	// 244字节
      bindex_t idx;
      binmap_t smallbits;
      // 修改申请的内存量,考虑malloc_chunk占用的内存,考虑8字节对齐问题.
      nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes);
      // 根据申请的内存大小计算在small bins中的索引号
      idx = small_index(nb);

      // 检查对应的链表或相邻链表中是否有空闲内存块
      smallbits = gm->smallmap >> idx;		
      if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */
        mchunkptr b, p;
        // 如果对应链表为空,就使用相邻链表中的内存块.
        idx += ~smallbits & 1;       /* Uses next bin if idx empty */
        b = smallbin_at(gm, idx);	// 取出这条链表
        p = b->fd;			// 这是链表中第一个空闲的内存块,也正是要分配给应用程序使用的内存块.

        assert(chunksize(p) == small_index2size(idx));
        unlink_first_small_chunk(gm, b, p, idx);	// 将p从链表中摘除
        // 对内存块做一些设置
        set_inuse_and_pinuse(gm, p, small_index2size(idx));
        mem = chunk2mem(p);	// 这是返还给应用程序的内存块的指针
        check_malloced_chunk(gm, mem, nb);	// 这是一个检查函数
        goto postaction;	// 找到了,返回吧.
      }  
      else if (nb > gm->dvsize) {	// 申请的内存量比last remainder要大,那么就不能使用last remainder了.
        // 但是其他链表中还有空闲内存块,从其他链表中分配.
        if (smallbits != 0) { /* Use chunk in next nonempty smallbin */
          // 首先需要做的事情就是在small bins中查找一条合适的链表,这条链表非空,并且与请求的内存量差距最小。
          mchunkptr b, p, r;
          size_t rsize;
          bindex_t i;
          binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx));
          binmap_t leastbit = least_bit(leftbits);	
          compute_bit2idx(leastbit, i);
          b = smallbin_at(gm, i);	// b就是找到的链表

          p = b->fd;	// 这是链表中第一个节点,也就是要分配个应用程序的内存块。
          assert(chunksize(p) == small_index2size(i));
          unlink_first_small_chunk(gm, b, p, i);	// 将这个节点从链表中摘除.
          rsize = small_index2size(i) - nb;	// 去除我们申请的内存后,这个chunk中剩余的空闲内存量.
          /* Fit here cannot be remainderless if 4byte sizes */
          if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)
            set_inuse_and_pinuse(gm, p, small_index2size(i));
          else { // chunk中剩余的内存量至少是8字节,因此可以继续作为一个独立的内存块使用.
            set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
            r = chunk_plus_offset(p, nb);	// 这就是分割nb后剩余的内存构成的新内存块.
            set_size_and_pinuse_of_free_chunk(r, rsize);
            replace_dv(gm, r, rsize);	// 用这个内存块替换掉dv,原先的dv保存在合适的链表中.
          }
          mem = chunk2mem(p);	// 这是返还给用户程序的缓冲区的指针.
          check_malloced_chunk(gm, mem, nb);
          goto postaction;
        } // end if (smallbits != 0)
        // small bins中没有空闲内存块了,因此使用tree bins中的内存块.
        // 由于这个内存块大于我们请求的内存量,因此将这个内存块划分成两个内存块,
        // 一个返回给用户程序使用ÿ
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
dlmalloc是目前一个十分流行的内存分配器,其由Doug Lea(主页为http://gee.cs.oswego.edu/)从1987年开始编写,到目前为止,最新版本为2.8.3(可以从ftp://g.oswego.edu/pub/misc/malloc.c获取),由于其高效率等特点被广泛的使用(比如一些linux系统等用的就是dlmalloc或其变形,比如ptmalloc,主页为http://www.malloc.de/en/index.html)和研究(各位可以搜索关键字“GCspy”)。 dlmalloc的实现只有一个源文件(还有一个头文件),大概5000行,其内注释占了大量篇幅,由于有这么多注释存在的情况下,表面上看上去很容易懂,的确如此,在不追求细节的情况,对其大致思想的确很容易了解(没错,就只是了解而已),但是dlmalloc作为一个高品质的佳作,实现上使用了非常多的技巧,在实现细节上不花费一定的精力是没有办法深入理解其为什么这么做,这么做的好处在哪,只有当真正读懂后回味起来才发现它是如此美妙。 lenky0401个人博客将陆续推出对dlmalloc的解析(针对Doug Lea Malloc的最新版Version 2.8.3,未做说明的情况下以32位平台,8字节对齐作为假定平台环境设置考虑),由于个人水平有限,因此也不能完全保证对dlmalloc的所有理解都准备无误, 但是所有内容均出自个人的理解而并非存心妄自揣测来愚人耳目,所以如果读者发现其中有什么错误,请勿见怪,如果可以则请来信告之,并欢迎来信讨论(lenky0401@163.com)。 这一系列文章是lenky0401在看完dlmalloc的大部分代码后的再总结,不能保证对dlmalloc的整体完全把握,贴出这些只是希望可以提前收到对此有研究的网友的指点,以便在最后对这一系列文章整理而形成的PDF文档中错误能少一些。至于对于现在贴出来的内容中包含的错误给大家造成的不便提前说声抱歉。:) 描述的内容不会包含dlmalloc全部代码,但会将这其中涉及到的一些技巧尽量讲出,我相信对dlmalloc源代码不感兴趣的朋友也可以学到这些独立的技巧而使用在自己的编程实践中。:) 最后,转载请保留本博客地址连接[http://lenky0401.cublog.cn],谢谢。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值