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 分钟前
最长递增子序列的个数(200分 / 动态规划)
算法·动态规划
镜子AI18 分钟前
教培机构多模态内容跨模态检索系统:基于CLIP的统一表征与图文混合召回算法
人工智能·python·算法·机器学习
小宋102129 分钟前
合成评测集怎么造才不“自嗨”:自动出题、去重、泄漏检测与人工抽检
人工智能·算法·机器学习
蒸蒸yyyyzwd42 分钟前
秋招笔记day58
算法·哈希算法
Jasmine_llq1 小时前
《P5663 [CSP-J 2019] 加工零件》
数据结构·算法·bfs·广度优先搜索·分层 bfs /·奇偶分层最短路·奇数最短步数
在所不辞兄1 小时前
分层PINN提升多物理场一致性
人工智能·神经网络·算法·机器学习·工程仿真
wanderist.1 小时前
CSP 第43次认证 T4:集合划分 —— 图染色与二分图判定
算法·图论
不做无法实现的梦~1 小时前
基于 PX4 的全仓库架构、无人机算法解析与开发学习规划
算法·架构·无人机
做cv的小昊1 小时前
【大模型算法自学笔记01】NLP基础知识(1.1 自注意力)
人工智能·笔记·算法·自然语言处理·大模型·llm
stolentime2 小时前
AT_arc182_a [ARC182A] Chmax Rush!题解
数据结构·c++·算法·动态规划