.Net GC从空闲列表里面分配对象

发表于:2023-10-08 09:19

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:江湖    来源:江湖评谈

  1.前言
  空闲列表(free_list)实质上是GC经过垃圾回收之后形成的碎片空间,它的空间可以进行重新分配新的对象。本篇看下它的重新分配过程。
  2.概述
  当进行一个对象分配的时候,如果是慢速分配(JIT_New)的时候,它会查找空闲列表里面是否有足够的空间来分配这个对象。如果有就把这个对象放到空闲列表里面去。
  CLR堆栈如下:
  >  WKS::gc_heap::a_fit_free_list_p  C++
     WKS::gc_heap::soh_try_fit  C++
     WKS::gc_heap::allocate_soh  C++
     WKS::gc_heap::try_allocate_more_space  C++
     WKS::gc_heap::allocate_more_space  C++
     WKS::gc_heap::allocate  C++
     WKS::GCHeap::Alloc  C++
     Alloc  C++
     AllocateObject  C++
     JIT_New  C++
  //此处省略一万行
     RtlUserThreadStart()  未知
  着重看下这个a_fit_free_list_p函数,它就是进行空闲列表分配,关键代码如下:
  BOOL gc_heap::a_fit_free_list_p (int gen_number,
                                   size_t size,
                                   alloc_context* acontext,
                                   uint32_t flags,
                                   int align_const)
  {
      BOOL can_fit = FALSE;
      //获取当前收集代地址
      generation* gen = generation_of (gen_number);
      //获取当前收集代 空闲列表一直
      allocator* gen_allocator = generation_allocator (gen);
      //遍历冫空闲列表里面的bucket,找到何时的空间存储对象
      for (unsigned int a_l_idx = gen_allocator->first_suitable_bucket(size); a_l_idx < gen_allocator->number_of_buckets(); a_l_idx++)
      {
          //索引的空闲列表的头部指针
          uint8_t* free_list = gen_allocator->alloc_list_head_of (a_l_idx);
          uint8_t* prev_free_item = 0;
          //如果获取到的空闲列表空间不为0
          while (free_list != 0)
          {
              //获取当前索引空闲了free_list里面bucket的长度
              size_t free_list_size = unused_array_size (free_list);
             //如果需要分配对象长度小于free_lis里面获取的长度,那么表示对象可以放入空闲列表
              if ((size + Align (min_obj_size, align_const)) <= free_list_size)
              {
                  //unlink,断开链接。意思是从空闲列表里面把空间拿出来,因为它操作的是链表。
                  // 把获取到的free_lsit的bucket长度从free_lsit链表里面拿掉,也就是个链表操作
                  gen_allocator->unlink_item (a_l_idx, free_list, prev_free_item, FALSE);
                  //计算出对象需要的空间也就是参数size,最终需要分配的长度
                  size_t limit = limit_from_size (size, flags, free_list_size, gen_number, align_const);
                  //收集代静态数据new_allocation减去对象最终分配空间大小
                  dd_new_allocation (dynamic_data_of (gen_number)) -= limit;
                  //空闲列表头部指针+对象占用空间大小,指向的是剩余的空间地址
                  uint8_t*  remain = (free_list + limit);
                  // 当前代的空闲列表大小减去分配对象的大小,剩余值remain_size
                  size_t remain_size = (free_list_size - limit);
                  //如果剩余值,大于或者等于一个空闲列表的大小
                  if (remain_size >= Align(min_free_list, align_const))
                  {
                     //重新把它作为空闲列表,放入free_list的bucket里面去
                      make_unused_array (remain, remain_size);
                      gen_allocator->thread_item_front (remain, remain_size);
                      assert (remain_size >= Align (min_obj_size, align_const));
                  }
                  else  //如果剩余值小于
                  {
                      //这里直接把剩余值给分配对象大小得了,也就是上面计算的分配对象大小+剩余的空间
                      limit += remain_size;
                  }
                  //代的空闲空间减去对象需要的空间 
                  generation_free_list_space (gen) -= limit;
                  assert ((ptrdiff_t)generation_free_list_space (gen) >= 0);
                  //把alloc_context指向计算的空间,对象就分配到alloc_context指向的地址
                  adjust_limit_clr (free_list, limit, size, acontext, flags, 0, align_const, gen_number);
                  can_fit = TRUE;
                  goto end;
              }         
          }
      }
  end:
      return can_fit;
  }
  以上整体的思路是:
  1.先找到当前垃圾回收的代。
  2.通过这个代找到次代的空闲列表。
  3.遍历循环空闲列表里的number_of_buckets,以找到合适的空间放置需要分配的对象。
  4.如果找到了此空间,就设置alloc_context指向此空间。对象分配就通过alloc_context来分配。
  它这个整体上是操作空闲列表管理类,然后通过空闲列表管理类给对象分配空间。
  本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号