__libc_malloc()源码阅读

本文详细探讨了__libc_malloc()的实现,涉及内存分配中的chunk转换、对齐策略、size计算、chunk状态管理以及bin操作等核心步骤。通过分析malloc源码,揭示了内存分配的内部逻辑,包括在small bin、fast bin和large bin中的查找与插入过程。
摘要由CSDN通过智能技术生成

malloc 源码

  • chunk 与 mem 指针头部的转换(mem 指向用户申请的内存空间)

    /* conversion from malloc headers to user pointers, and back */
    #define chunk2mem(p) ((void *) ((char *) (p) + 2 * SIZE_SZ))
    #define mem2chunk(mem) ((mchunkptr)((char *) (mem) -2 * SIZE_SZ))
    
  • 检查分配给用户的内存是否对齐,2 * SIZE_SZ 大小对齐。

    /* Check if m has acceptable alignment */
    // MALLOC_ALIGN_MASK = 2 * SIZE_SZ -1
    #define aligned_OK(m) (((unsigned long) (m) & MALLOC_ALIGN_MASK) == 0)
    
    #define misaligned_chunk(p)                                                    \
        ((uintptr_t)(MALLOC_ALIGNMENT == 2 * SIZE_SZ ? (p) : chunk2mem(p)) &       \
         MALLOC_ALIGN_MASK)
    
  • 将用户请求内存大小转为实际分配内存大小

    /* pad request bytes into a usable size -- internal version */
    //MALLOC_ALIGN_MASK = 2 * SIZE_SZ -1
    #define request2size(req)                                                      \
        (((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE)                           \
             ? MINSIZE                                                             \
             : ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)
    
    /*  Same, except also perform argument check */
    
    #define checked_request2size(req, sz)                                          \
        if (REQUEST_OUT_OF_RANGE(req)) {                                           \
            __set_errno(ENOMEM);                                                   \
            return 0;                                                              \
        }                                                                          \
        (sz) = request2size(req);
    
  • 标记位相关

    /* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */
    #define PREV_INUSE 0x1
    
    /* extract inuse bit of previous chunk */
    #define prev_inuse(p) ((p)->mchunk_size & PREV_INUSE)
    
    /* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */
    #define IS_MMAPPED 0x2
    
    /* check for mmap()'ed chunk */
    #define chunk_is_mmapped(p) ((p)->mchunk_size & IS_MMAPPED)
    
    /* size field is or'ed with NON_MAIN_ARENA if the chunk was obtained
       from a non-main arena.  This is only set immediately before handing
       the chunk to the user, if necessary.  */
    #define NON_MAIN_ARENA 0x4
    
    /* Check for chunk from main arena.  */
    #define chunk_main_arena(p) (((p)->mchunk_size & NON_MAIN_ARENA) == 0)
    
    /* Mark a chunk as not being on the main arena.  */
    #define set_non_main_arena(p) ((p)->mchunk_size |= NON_MAIN_ARENA)
    
    /*
       Bits to mask off when extracting size
       Note: IS_MMAPPED is intentionally not masked off from size field in
       macros for which mmapped chunks should never be seen. This should
       cause helpful core dumps to occur if it is tried by accident by
       people extending or adapting this malloc.
     */
    #define SIZE_BITS (PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
    
  • 获取 chunk size

    /* Get size, ignoring use bits */
    #define chunksize(p) (chunksize_nomask(p) & ~(SIZE_BITS))
    
    /* Like chunksize, but do not mask SIZE_BITS.  */
    #define chunksize_nomask(p) ((p)->mchunk_size)
    
  • 获取下一个物理相邻的 chunk

    /* Ptr to next physical malloc_chunk. */
    #define next_chunk(p) ((mchunkptr)(((char *) (p)) + chunksize(p)))
    
  • 获取前一个 chunk 的信息

    /* Size of the chunk below P.  Only valid if !prev_inuse (P).  */
    #define prev_size(p) ((p)->mchunk_prev_size)
    
    /* Set the size of the chunk below P.  Only valid if !prev_inuse (P).  */
    #define set_prev_size(p, sz) ((p)->mchunk_prev_size = (sz))
    
    /* Ptr to previous physical malloc_chunk.  Only valid if !prev_inuse (P).  */
    #define prev_chunk(p) ((mchunkptr)(((char *) (p)) - prev_size(p)))
    
  • 当前 chunk 使用状态相关操作

    /* extract p's inuse bit */
    #define inuse(p)                                                               \
        ((((mchunkptr)(((char *) (p)) + chunksize(p)))->mchunk_size) & PREV_INUSE)
    
    /* set/clear chunk as being inuse without otherwise disturbing */
    #define set_inuse(p)                                                           \
        ((mchunkptr)(((char *) (p)) + chunksize(p)))->mchunk_size |= PREV_INUSE
    
    #define clear_inuse(p)                                                         \
        ((mchunkptr)(((char *) (p)) + chunksize(p)))->mchunk_size &= ~(PREV_INUSE)
    
  • 设置 chunk 的 size 字段

    /* Set size at head, without disturbing its use bit */
    // SIZE_BITS = 7
    #define set_head_size(p, s)                                                    \
        ((p)->mchunk_size = (((p)->mchunk_size & SIZE_BITS) | (s)))
    
    /* Set size/use field */
    #define set_head(p, s) ((p)->mchunk_size = (s))
    
    /* Set size at footer (only when chunk is not in use) */
    #define set_foot(p, s)                                                         \
        (((mchunkptr)((char *) (p) + (s)))->mchunk_prev_size = (s))
    
  • 获取指定偏移的 chunk

    /* Treat space at ptr + offset as a chunk */
    #define chunk_at_offset(p, s) ((mchunkptr)(((char *) (p)) + (s)))
    
  • 指定偏移处 chunk 使用状态相关操作

    /* check/set/clear inuse bits in known places */
    #define inuse_bit_at_offset(p, s)                                              \
        (((mchunkptr)(((char *) (p)) + (s)))->mchunk_size & PREV_INUSE)
    
    #define set_inuse_bit_at_offset(p, s)                                          \
        (((mchunkptr)(((char *) (p)) + (s)))->mchunk_size |= PREV_INUSE)
    
    #define clear_inuse_bit_at_offset(p, s)                                        \
        (((mchunkptr)(((char *) (p)) + (s)))->mchunk_size &= ~(PREV_INUSE))
    
  • __libc_malloc()

    void *
    __libc_malloc (size_t bytes)
    {
         
      mstate ar_ptr;
      void *victim;
    
      _Static_assert (PTRDIFF_MAX <= SIZE_MAX / 2,
                      "PTRDIFF_MAX is not more than half of SIZE_MAX");
      //读取__malloc_hook钩子,如果有钩子,则先运行钩子函数
      void *(*hook) (size_t, const void *)
        = atomic_forced_read (__malloc_hook);
      if (__builtin_expect (hook != NULL, 0))
        return (*hook)(bytes, RETURN_ADDRESS (0));
      
      //使用TACHE的情况下,如果tache中有符合大小的chunk则直接分配
    #if USE_TCACHE
      /* int_free als0 calls request2size, be careful to not pad twice.  */
      size_t tbytes;
      if (!checked_request2size (bytes, &tbytes))
        {
         
          __set_errno (ENOMEM);
          return NULL;
        }
      size_t tc_idx = csize2tidx (tbytes);
    
      MAYBE_INIT_TCACHE ();
    
      DIAG_PUSH_NEEDS_COMMENT;
      if (tc_idx < mp_.tcache_bins
          && tcache
          && tcache->counts[tc_idx] > 0)
        {
         
          return tcache_get (tc_idx);
        }
      DIAG_POP_NEEDS_COMMENT;
    #endif
        
        if (SINGLE_THREAD_P)
        {
         
          victim = _int_malloc (&main_arena, bytes); 
          assert (!victim || chunk_is_mmapped (mem2chunk (victim)) ||
                  &main_arena == arena_for_chunk (mem2chunk (victim)));
          return victim;
        }
    
      arena_get (ar_ptr, bytes); //寻找一个合适的arena分配内存
    
      victim = _int_malloc (ar_ptr, bytes); //分配内存的核心函数
      /* Retry with another arena only if we were able to find a usable arena
         before.  */
      if (!victim && ar_ptr != NULL)
        {
         
          LIBC_PROBE (memory_malloc_retry, 1, bytes);
          ar_ptr = arena_get_retry (ar_ptr, bytes);
          victim = _int_malloc (ar_ptr, bytes);
        }
    
      if (ar_ptr != NULL) //如果申请了arena,还需要进行解锁
        __libc_lock_unlock (ar_ptr->mutex);
    
      assert (!victim || chunk_is_mmapped (mem2chunk (victim)) ||
              ar_ptr == arena_for_chunk (mem2chunk (victim)));
      return victim;
    }
    
  • _int_malloc

    static void *
    _int_malloc (mstate av, size_t bytes)
    {
         
      INTERNAL_SIZE_T nb;               /* normalized request size */
      unsigned int idx;                 /* associated bin index */
      mbinptr bin;                      /* associated bin */
    
      mchunkptr victim;                 /* inspected/selected chunk */
      INTERNAL_SIZE_T size;             /* its size */
      int victim_index;                 /* its bin index */
    
      mchunkptr remainder;              /* remainder from a split */
      unsigned long remainder_size;     /* its size */
    
      unsigned int block;               /* bit map traverser */
      unsigned int bit;                 /* bit map traverser */
      unsigned int map;                 /* current word of binmap */
    
      mchunkptr fwd;                    /* misc temp for linking */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值