ptmalloc源码分析 - _int_malloc函数实现smallbins/unsorted bin(07)

目录

一、smallbins的定义和空闲链表的使用条件

二、smallbins的具体实现

三、malloc_consolidate整理操作

[四、unsorted bin的具体实现](#四、unsorted bin的具体实现)


前一章,我们讲解了fastbins的空闲链表的分配逻辑。这一章,我们主要讲一下smallbins和unsorted bin的分配逻辑。

一、smallbins的定义和空闲链表的使用条件


smallbins的定义:

  • smallbins放置在malloc_state-> bins数组上,数组从2开始编号到63,前62个bin为small bins
  • 小于**512字节(64位机器1024字节)**的chunk被称为small chunk,而保存small chunks的bin被称为small bin
  • small bin每个bin之间相差**8个字节(**64位16字节),同一个small bin中的chunk具有相同大小。起始bin大小为16字节(64位系统32)。

smallbins空闲链表的使用条件:

  • 需要符合 smallbin的大小,并且空闲链表上正好有空闲的chunk,则可以分配
  • 数组对应的chunk链表,默认情况下需要有2个及以上的元素,才能分配。如果只有一个chunk,则这个chunk是用于管理和连接链表的

二、smallbins的具体实现


具体的实现步骤如下:

  1. 如果符合smallbin的大小,则从smallbin的数组上获取一个chunk进行内存分配

  2. 如果是smallbin,则通过bins的数组下标获取到对应的chunk双向链表

  3. 如果空闲链表中有空闲的chunk,然后从链表的尾部通过弹出一个chunk,并修改双向链表

  4. 如果空闲链表中没有空闲的chunk,则此次分配失败,需要跳出smallbins上的分配逻辑,往下走其他逻辑的分配方式

  5. 获取得到的victim就是要操作的内存chunk对象,通过chunk2mem和alloc_perturb函数,初始化对象

cpp 复制代码
 /*
   * 如果符合smallbin的大小,则从smallbin的数组上获取一个chunk进行内存分配,如果存在空闲chunk则分配成功;如果空闲链表为空,则分配失败需要往下走
   * 1. 如果是smallbin,则通过bins的数组下标获取到对应的chunk双向链表
   * 2. 然后从链表的尾部通过弹出一个chunk,并修改双向链表
   * 3. 获取得到的victim就是要操作的内存chunk对象,通过chunk2mem和alloc_perturb函数,初始化对象 */
  if (in_smallbin_range (nb))
    {
      idx = smallbin_index (nb); //获取smallbin的数组下标
      bin = bin_at (av, idx); //av->获取数组上的bin ; bins数组为:mchunkptr结构的数组

      //只有bin这个chunk双向链表有2个以上值,才会分配
      //bin是mchunkptr结构的链表(双向链表);last(bin) 获取bin->bk,获取最后一个chunk;从链表的尾部,取一个victim
      //Case1: A -> B -> C -> D 四个chunk,则取出D,调整双向链表:A -> B -> C
      //Case2: A -> B 两个chunk,则取出B,调整双向链表:A->bk = A / A->fd = A
      if ((victim = last (bin)) != bin)
        {
          bck = victim->bk; //获取victim的前一个bin
	  if (__glibc_unlikely (bck->fd != victim))
	    malloc_printerr ("malloc(): smallbin double linked list corrupted");
          set_inuse_bit_at_offset (victim, nb); //将victim设置为已使用状态
          bin->bk = bck; //将bin->bk设置为bck
          bck->fd = bin; //将bck->fd设置为bin

          if (av != &main_arena)
	    set_non_main_arena (victim);
          check_malloced_chunk (av, victim, nb);
 
..................简

          void *p = chunk2mem (victim); //通过chunk结构,获取data数据部分的指针地址
          alloc_perturb (p, bytes); //初始化内存块
          return p;
        }
    }

三、malloc_consolidate整理操作


如果是largebin,则会把fast bin中的chunk进行一次整理合并。然后将合并后的chunk放入unsorted bin中,这是通过malloc_consolidate这个函数完成。核心逻辑就是进行一次碎片化整理。

malloc_consolidate具体不展开了,核心处理逻辑:

  1. 遍历fastbins,针对里面的chunk进行一次循环遍历操作,检查每个chunk的前一个和后一个chunk是否是free状态,如果是free状态,则合并
  2. 如果合并后的chunk不和top chunk挨着,则将这个chunk放进unsorted bins中
  3. 如果合并后的chunk和top chunk挨着,则重新设置top chunk的起始位置
cpp 复制代码
  /*
     If this is a large request, consolidate fastbins before continuing.
     While it might look excessive to kill all fastbins before
     even seeing if there is space available, this avoids
     fragmentation problems normally associated with fastbins.
     Also, in practice, programs tend to have runs of either small or
     large requests, but less often mixtures, so consolidation is not
     invoked all that often in most programs. And the programs that
     it is called frequently in otherwise tend to fragment.
   */

  else
    {
	  /* 如果是largebin,则会把fast bin中的chunk进行一次整理合并
	   * 然后将合并后的chunk放入unsorted bin中,这是通过malloc_consolidate这个函数完成*/
      idx = largebin_index (nb);
      if (atomic_load_relaxed (&av->have_fastchunks))
        malloc_consolidate (av);
    }

四、unsorted bin的具体实现


unsorted bin的定义:

  • 是bins的一个缓冲区,bins数组下标为1的即是unstored bin,被释放后未存储的bin
  • 当用户释放的内存大于max_fast或者fast bins合并后的chunk都会进入unsorted bin上
  • 当用户malloc的时候,如果fastbins和smallbins没有分配成功,则会到unsorted bin上查找是否有合适的bin,如果没有合适的bin,ptmalloc会将unsorted bin上的chunk放入bins上,然后到bins上查找合适的空闲chunk。

核心处理流程:

  1. 从unsorted bin的双向链表上去循环遍历每一个未存储的chunk,进行内存分配或者重新放置到smallbins和largebins上去

  2. 如果,我们分配的是一个small类型的,遇到合适大小的chunk,则可以将chunk进行切割,并且切割后返回分配的内存chunk

  3. 如果,请求的大小,正好和chunk大小匹配,则直接分配成功

  4. 如果,上面两步的分配都不成功,则将该chunk根据大小类型,放置到smallbins或者largebins上去

  5. 最后,继续开始循环迭代操作

cpp 复制代码
  //尝试从unsorted bin中分配
  for (;; )
    {
      int iters = 0;
      //从unsorted bin的双向链表上去循环处理,直到循环回到起始节点
      //unsorted bin放置在av->bins[1]的数组上,也是chunk类型的双向链表
      while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))
        {
          bck = victim->bk; //获取前一个chunk
          //确认当前chunk的大小,因为unsorted bin放置的是整理后的bin,大小并不是由small bin和large bin这种数组下标来决定的
          size = chunksize (victim);
          mchunkptr next = chunk_at_offset (victim, size); //获取内存块上相邻的下一个chunk的地址,这个不是双向链表上的,是内存相邻的chunk

.............简

          /*
           * 分配的是small类型的并且小于当前的chunk,则可以进行切割分配
           * 几个条件:
           * 1. 需要符合smallbin
           * 2. unsorted bins上只剩下一个bin
           * 3. 当前的chunk等于last_remainder
           * 4. size需要大于nb,并且分割后的last_remainder,仍然可以使用*/
          if (in_smallbin_range (nb) &&
              bck == unsorted_chunks (av) &&
              victim == av->last_remainder &&
              (unsigned long) (size) > (unsigned long) (nb + MINSIZE))
            {
              /* split and reattach remainder 进行chunk的切割操作 */
              remainder_size = size - nb; //remainder的大小
              remainder = chunk_at_offset (victim, nb); //remainder指针地址
              unsorted_chunks (av)->bk = unsorted_chunks (av)->fd = remainder;
              av->last_remainder = remainder;
              remainder->bk = remainder->fd = unsorted_chunks (av);
              if (!in_smallbin_range (remainder_size))
                {
                  remainder->fd_nextsize = NULL;
                  remainder->bk_nextsize = NULL;
                }

              set_head (victim, nb | PREV_INUSE |
                        (av != &main_arena ? NON_MAIN_ARENA : 0)); //设置mchunk_size 大小
              set_head (remainder, remainder_size | PREV_INUSE); //设置mchunk_size 大小
              set_foot (remainder, remainder_size); //设置下一个chunk->mchunk_prev_size

              check_malloced_chunk (av, victim, nb);
              void *p = chunk2mem (victim); //通过chunk结构,获取data数据部分的指针地址
              alloc_perturb (p, bytes); //初始化内存块
              return p;
            }

          /* remove from unsorted list */
          if (__glibc_unlikely (bck->fd != victim))
            malloc_printerr ("malloc(): corrupted unsorted chunks 3");
          unsorted_chunks (av)->bk = bck;
          bck->fd = unsorted_chunks (av);

          /* Take now instead of binning if exact fit */
          /* 请求的大小,正好和chunk大小匹配,则直接分配成功 */
          if (size == nb)
            {
              set_inuse_bit_at_offset (victim, size); //将victim设置为已使用状态
              if (av != &main_arena)
		set_non_main_arena (victim);
............简
              check_malloced_chunk (av, victim, nb);
              void *p = chunk2mem (victim);//通过chunk结构,获取data数据部分的指针地址
              alloc_perturb (p, bytes);//初始化内存块
              return p;

            }

          /* place chunk in bin */
          //当前chunk属于small bin的范围,将其放回small bin
          if (in_smallbin_range (size))
            {
              victim_index = smallbin_index (size);
              bck = bin_at (av, victim_index);
              fwd = bck->fd;
            }
          else //当前chunk属于large bin的范围,将其放回large bin
            {
              victim_index = largebin_index (size);
              bck = bin_at (av, victim_index);
              fwd = bck->fd;

          ................简

          mark_bin (av, victim_index);
          // bck -> fwd 插入victim   bck -> victim -> fwd
          victim->bk = bck;
          victim->fd = fwd;
          fwd->bk = victim;
          bck->fd = victim;



#define MAX_ITERS       10000
          //循环最多10000次,则结束
          if (++iters >= MAX_ITERS)
            break;
        }

下一章节,我们继续看_int_malloc函数里面的largebins和topchunk的实现

相关推荐
从以前1 小时前
【算法题解】Bindian 山丘信号问题(E. Bindian Signaling)
开发语言·python·算法
不白兰1 小时前
[代码随想录23回溯]回溯的组合问题+分割子串
算法
御风@户外2 小时前
质数生成函数、质数判断备份
算法·acm
闻缺陷则喜何志丹2 小时前
【C++动态规划】1105. 填充书架|2104
c++·算法·动态规划·力扣·高度·最小·书架
Dong雨2 小时前
六大排序算法:插入排序、希尔排序、选择排序、冒泡排序、堆排序、快速排序
数据结构·算法·排序算法
达帮主2 小时前
7.C语言 宏(Macro) 宏定义,宏函数
linux·c语言·算法
是十一月末3 小时前
机器学习之KNN算法预测数据和数据可视化
人工智能·python·算法·机器学习·信息可视化
chenziang13 小时前
leetcode hot100 路径总和
算法
lyx1426063 小时前
leetcode 3083. 字符串及其反转中是否存在同一子字符串
算法·leetcode·职场和发展
茶猫_3 小时前
力扣面试题 39 - 三步问题 C语言解法
c语言·数据结构·算法·leetcode·职场和发展