malloc_state

一般像glibc这种大型的工程都是需要用面向对象的方法来设计的,尽管c语言不支持这种特性但是设计者还是使用了一些面向对象的思维,这个malloc_state就是很明显的体现。

struct malloc_state
{
  // 线程锁,当多线程进行内存分配竞争的时候,需要首先拿到该锁才能进行分配区上的操作  
  __libc_lock_define (, mutex);

  // 记录了分配区的一些标志,比如 bit0 记录了分配区是否有 fastbin,bit1 标识分配区是否能返回连续的虚拟地址空间  
  int flags;

  // 用于标记是否有fast bins  
  /* 表示为布尔值,但使用 int 类型是为了兼容不支持原子操作的目标平台 */
  int have_fastchunks;

  /* 定义:typedef struct malloc_chunk *mfastbinptr; */
  // fastbins的实例 
  mfastbinptr fastbinsY[NFASTBINS];

  // 指向分配区的 top chunk
  mchunkptr top;

  // 最新的 chunk 分割之后剩下的那部分 
  mchunkptr last_remainder;

  // 用于存储双向链表
  mchunkptr bins[NBINS * 2 - 2];

  //这里用同一个数据定义了三个不同意义的变量,方便我们用数据组合出的新数据命名以提供抽象化操作

  // 标识某一个 bin 中是否包含空闲 chunk 
  unsigned int binmap[BINMAPSIZE];


  /* 下面这几个成员主要是用于多线程操作的 */

  // 分配区全局链表,主分配区放头部,新加入的分配区放main_arean.next 位置 
  struct malloc_state *next;
  // 空闲的分配区 
  struct malloc_state *next_free;
  /* 表示当前附加到这个内存分配区域的线程数量。如果该值为 0,表示该区域在空闲列表中。访问该字段的操作也受到 free_list_lock 的保护 */
  INTERNAL_SIZE_T attached_threads;

  // Memory allocated from the system in this arena.  
  INTERNAL_SIZE_T system_mem;
  INTERNAL_SIZE_T max_system_mem;
};

这里面的成员其实联系并不那么紧密所以第一次学的时候还是很懵的。但是将其设计成一个类,减小成员的数量到只涉及fastbin相关并且加入一些使用频率较高的函数作为方法(比如chunk2mem或者是将nb转换为idx的宏),然后在对应流程时用继承特性拓展该类就不仅可以更好的管理类还可以更好的结构化代码了

在自己记忆源码时就可以这样去想

malloc_consolidate

这个函数主要作用是:将fastbin放入unsortedbin并把相邻的非fastbin合并,并清除该fastbin的inuse位

static void malloc_consolidate(mstate av)
  atomic_store_relaxed (&av->have_fastchunks, false);
  unsorted_bin = unsorted_chunks(av);

  maxfb = &fastbin (av, NFASTBINS - 1); /* maxfb指向fastbin数组的最后一个元素,也就是fastbinY[9] */
  fb = &fastbin (av, 0);/* 同理,指向fastbin数组的第一个元素,也就是fastbinY[0] */
  do 
  {
    p = atomic_exchange_acq (fb, NULL);  // 相当于p = fastbinY[now_idx],fastbinY[now_idx]=NULL

    if (p != 0) 
    {
      do 
      {
	{
	  unsigned int idx = fastbin_index (chunksize (p));
	  if ((&fastbin (av, idx)) != fb)
	    malloc_printerr ("malloc_consolidate(): invalid chunk size");
	}

	check_inuse_chunk(av, p); // 相当于[(p+chunksize)->size] & 1 
	nextp = p->fd;  

	size = chunksize (p);   // 得到除去A、M、P标志位之后的size域 
	nextchunk = chunk_at_offset(p, size);  // 将位于p+size(char*指针的运算)处的内存区域视为一个malloc_chunk,并将对应的指针返回
	nextsize = chunksize(nextchunk);

	if (!prev_inuse(p)) //相当于(p->msize) & 1
    {
	  prevsize = prev_size (p);     
	  size += prevsize;         
	  p = chunk_at_offset(p, -((long) prevsize)); // 向前合并
	  unlink(av, p, bck, fwd);    // 因为合并的是bins中的chunk所以需要unlink 
	}

	if (nextchunk != av->top) 
    {
	  nextinuse = inuse_bit_at_offset(nextchunk, nextsize);/* 相当于(nextchunk+size)->size & 1,也就是检查下一个chunk是否free */

	  if (!nextinuse) 
      {
	    size += nextsize; //向后合并
	    unlink(av, nextchunk, bck, fwd);
	  } 
      else
	    clear_inuse_bit_at_offset(nextchunk, 0); //该fastbin入unsortedbin了,下一个chunk的inuse位要清除

	  first_unsorted = unsorted_bin->fd;
	  unsorted_bin->fd = p;
	  first_unsorted->bk = p;      // 头插法将p插入到unsorted_bin,半入链 

	  if (!in_smallbin_range (size)) //如果合并了largebin,清除size指针
      {
	    p->fd_nextsize = NULL;    
	    p->bk_nextsize = NULL;
	  }

	  set_head(p, size | PREV_INUSE);   //相当于p->size=size,设置p chunk的size为(size|PREV_INUSE)
	  p->bk = unsorted_bin;  
	  p->fd = first_unsorted;
		//设置完fd和bk位之后,p chunk才算是链入到了unsortedbin中
	  set_foot(p, size); //(p+size)->size=size,设置下一个chunk的mchunk_prev_size
	}
	else 
    {  // 下一个chunk使是topchunk直接合并进去
	  size += nextsize;
	  set_head(p, size | PREV_INUSE);
	  av->top = p;
	}

      } while ( (p = nextp) != 0); //直到遍历完当前fastbinY[idx]链表中所有free chunk) 

    }
  } 
  while (fb++ != maxfb);  // 指针运算使fb指向fastbinY[now_idx+1],直到整个fastbin数组都被处理完 
}

每一个双向链表出链的操作

unlink(AV, P, BK, FD) 
{                                            
    if (__builtin_expect (chunksize(P) != prev_size (next_chunk(P)), 0))  // 检查该chunk的size和next chunk的prev_size是否相等 
      malloc_printerr ("corrupted size vs. prev_size");			      
    
    FD = P->fd;		// FD=fwd,BK=bck
    BK = P->bk;			    
    if (__builtin_expect (FD->bk != P || BK->fd != P, 0))	
      malloc_printerr ("corrupted double-linked list");			      
    else 
    {								      
        FD->bk = BK;	// 取出该chunk 
        BK->fd = FD;

        if (  (!in_smallbin_range (chunksize_nomask (P)))  &&  (P->fd_nextsize != NULL)  )
        {		      
	    if (  (P->fd_nextsize->bk_nextsize != P) || (P->bk_nextsize->fd_nextsize != P)  )  //如果是有size指针的largebin
	      malloc_printerr ("corrupted double-linked list (not small)");   
            if (FD->fd_nextsize == NULL)    
            {				      
                if (P->fd_nextsize == P)	    
                  FD->fd_nextsize = FD->bk_nextsize = FD;		   // 该组bin有同size的bin 且 是bins中唯一size的bin      
                else   //最复杂的情况,该组bin有多个size的bin,且不是bins中唯一size的bin
                {						      
                    FD->fd_nextsize = P->fd_nextsize;			      
                    FD->bk_nextsize = P->bk_nextsize;			      
                    P->fd_nextsize->bk_nextsize = FD;			      
                    P->bk_nextsize->fd_nextsize = FD;			      
                }							      
            } 
            else    //该bins只有一个bin或者bin都没用同size的其它bin(只有竖着的size链)
            {							      
                P->fd_nextsize->bk_nextsize = P->bk_nextsize;		      
                P->bk_nextsize->fd_nextsize = P->fd_nextsize;		      
            }								      
          }								      
      }									      
}