• .Net CLR GC 动态加载短暂堆阈值的计算及阈值超量的计算


    楔子

    今天你躺平了吗?生活是如此的无趣,欢迎大家一起来躺平

    前言:

    很多书籍或者很多文章,对于CLR或者GC这块只限于长篇大论的理论性概念,对于里面的如何运作模式,却几乎一无所知。高达近百万行的CPP文件,毕竟读懂的没有几个。以下取自CLR.Net 6 PreView版本

    分配量超过阈值

    GC触发里面有一个GC被触发的条件是,分配的内存块超过阈值。这个阈值是在Generation代里面的static_data里面的存储的固定数值。当你分配的内存块超过这个阈值的时候,就会触发GC进行垃圾回收。来看看这个阈值动态加载和超过阈值触发GC垃圾回收之后,重新计算阈值的算法。

    初始化

    在CLR启动的时候,会初始化Generation的静态数据,此时会填充阈值。
    Generation的部分静态数据结构:

    struct static_data
    {
        size_t min_size; 阈值的下限
        size_t max_size; 阈值的上限
        size_t fragmentation_limit; 碎片空间的上限
        float fragmentation_burden_limit; 碎片空间百分比的上限
        float limit; 限度的下限
        float max_limit; 限度的上限
        uint64_t time_clock; 
        size_t gc_clock; 
    };
    

    下面是GC定义的初始化参数数值,以上面的结构参考下面:

    static static_data static_data_table[latency_level_last - latency_level_first + 1][total_generation_count] =
    {
        {
            // gen0
            {0, 0, 40000, 0.5f, 9.0f, 20.0f, (1000 * 1000), 1},
            // gen1
            {160*1024, 0, 80000, 0.5f, 2.0f, 7.0f, (10 * 1000 * 1000), 10},
            // gen2
            {256*1024, SSIZE_T_MAX, 200000, 0.25f, 1.2f, 1.8f, (100 * 1000 * 1000), 100},
            // loh
            {3*1024*1024, SSIZE_T_MAX, 0, 0.0f, 1.25f, 4.5f, 0, 0},
            // poh
            {3*1024*1024, SSIZE_T_MAX, 0, 0.0f, 1.25f, 4.5f, 0, 0},
        }
    }
    

    直接套用:

    0代: 阈值下限0,无限制,限度下限9,限度上限20
    1代: 阈值下限160kb,无限制,限度下限2,限度上限7
    2代:  阈值下限256kb,无限制,限度下限1.2,限度上限1.6
    

    这是最初始化的值,什么意思呢?简而言之,就是CLR在加载此初始化的值的之后,进行了动态的分配的阈值的上下限。也就是说实际上GC的阈值和这里面表明的静态数值有差别。
    下面计算均为函数init_static_data里面
    0代阈值的下限动态计算方式(以工作站模式为例):

    1.通过gc的配置文件(gcconfig)来获取配置文件里面配置的值,如果获取此值失败则跳转到第二步
    2.通过windows API GetLogicalProcessorInformation获取到你当前电脑处理器最大的缓存值
    3.下面就是GC第0代阈值的算法了
    0代阈值下限= = max((4*你当前电脑处理器最大缓存值/5),(256*1024))
    你当前电脑处理器最大缓存值 =  max(你当前电脑处理器最大缓存值, (256*1024))
    while(如果0代阈值下限*处理器个数>你当前堆分配物理内存总大小/6)
    {
      0代阈值下限 = 0代阈值下限/2
      if(0代阈值下限 <=你当前电脑处理器最大缓存值 )
      {
        0代阈值下限 = 你当前电脑处理器最大缓存值
      }
    }
    if( 0代阈值下限 > = 小对象堆段(SOH)/2)
    {
       0代阈值下限 = 小对象堆段(SOH)/2
    }
    0代阈值下限 = 0代阈值下限 / 8 * 5;// 到了这里才是最终第0代阈值的下限,而非上面generaton的静态数据static_data_table里面的下限阈值为0.
    

    第0代阈值的上限呢?(此处同时看下服务器模式和工作站模式)

    服务器模式0代阈值上限的算法:
    0代阈值上限=max (6*1024*1024, min ( Align(soh_segment_size/2), 200*1024*1024))
    工作站模式0代阈值上限的算法
    0代阈值上限= max (0代阈值的下限,0代阈值的上限)
    0代阈值上限 = Align (0代阈值的下限)
    

    第1代阈值的上限(服务器模式和工作站模式)

    1代阈值的下限是160kb,那么上限呢?
    服务器模式1代阈值的上限=max (6*1024*1024, Align(小对象堆的大小/2));
    工作站模式1代阈值的上限=gen1_max_size = Align (服务器模式1代阈值的上限/0)
    

    阈值上限的重新计算

    当阈值上限的剩余空间不足以容纳当前CLR分配的内存块的时候,就造成了GC。GC之后,就会重新计算这个阈值的上限。这里是算法

    if(GC开始前存活的对象为0)
    {
       阈值的上限 = 当前代的阈值下限
    }
    else
    {
       if(当前代 >= 第二代)
       {
         cst = min (1.0f, float (GC之后活着的对象大小) / float (GC之前活着对象大小));
        if(cst<((限度的上限-限度的下限)/(限度的下限*(限度的上限 - 1.0f)))    
    	{
           限度= ((限度的下限 - 限度的下限* cst)/ (1.0f - (cst * 限度的下限)))
        }
    	else
    	  限度 = 限度的上限
    	  
    	size_t max_growth_size = (限度的上限 / 限度)
    	if( 当前代的大小 > = max_growth_size)
    	 新分配量= 阈值的上限
    	 else
    	 {
    	   新分配量 = (size_t) min (max ( (限度 * 当前代的大小), gc的最小值), 限度的上限);
    	   限度的上限 =  max((新分配量 - 当前代的大小),gc的最小值);
    	 }
      }
       else //如果是第二代以内的GC
       {
         cst = GC后活着的对象大小/ GC前活着对象大小
    	     if (cst < ((限度的上限 - 限度的下限) / (限度的下限 * (限度的上限-1.0f))))
            限度=  ((限度的下限 - 限度的上限*cst) / (1.0f - (cst * 限度的下限)));
        else
            限度= 限度的上限;
    		
        阈值的上限=min (max ((f * (GC后活着对象的大小)), 限度的下限), 限度的上限);
    
       }
    }
    
    折叠

    由于这个过程过于复杂,中间很多细节。但是大体都是这样。

    以上参考如下:
    https://github.com/dotnet/runtime/tree/main/src/coreclr/gc
    微信公众号:jianghupt QQ群:676817308

  • 相关阅读:
    JAVA知识点笔记
    Electron学习——解决npm install electron --save-dev出错/缓慢的问题
    Vue3 快速上手从0到1,两小时学会【附源码】
    QT基础 柱状图
    Python的2042小游戏及其详解
    【TensorFlow&PyTorch】创建张量学习笔记
    【我的前端】CSS启示录:CSS写出超级美观的阴影效果
    for循环三种跳出循环的方法(retrun、continue、break)
    wordpress 付费主题modown分享,可实现资源付费
    Qt Design Studio 4.5现已发布
  • 原文地址:https://www.cnblogs.com/tangyanzhi1111/p/16521379.html