.NET9 PreView7 DATAS原理简析

点击上方蓝字 江湖评谈设为关注/星标

0ef6d03dc2ea5310b37a7f9dbe865a4b.png

前言

之前(.NET9 Pre7 DATAS+Rustc Compile线程续)提到过DATAS的一些概念,本篇简析下它的原理。

.NET9 PreView7 中引入的动态适应应用程序大小(Dynamic Adaptation To Application Sizes,简称DATAS)功能。DATAS旨在根据应用程序的内存需求自动调整堆大小,使其与长期存活数据的大小大致成正比。它不同于SVR GC的呆板僵硬,它对于每个不同机器的不同配置分配的堆是不一样的。

详细

来看下它的原理,实际上所有的dotnet性能上的优化都可以通过配置文件进行解析和设置的。

DATAS的配置文件如下:

INT_CONFIG (GCDynamicAdaptationMode,"GCDynamicAdaptationMode", "System.GC.DynamicAdaptationMode",1, "Enable the GC to dynamically adapt to application sizes.")

INT_CONFIG

#define INT_CONFIG(name, unused_private_key, unused_public_key, default, unused_doc)  \
  int64_t GCConfig::Get##name() { return s_##name; }                                  \
  int64_t GCConfig::Get##name(int64_t defaultValue)                                   \
  {                                                                                   \
      return s_##name##Provided ? s_##name : defaultValue;                            \
  }                                                                                   \
  void GCConfig::Set##name(int64_t value) { s_Updated##name = value; }                \
  int64_t GCConfig::s_##name = default;                                               \
  bool GCConfig::s_##name##Provided = false;                                          \
  int64_t GCConfig::s_Updated##name = default;

我们看到它的default即是1.‍

这里其实可以扩展下,9 PreView7默认开启了,如果想要禁用:

export DOTNET_GCDynamicAdaptationMode=0

也即是上面的DATAS的配置文件加上dotnet_头即可形成环境变量的控制,比如HeapCount,它的配置如下:

INT_CONFIG (HeapCount,"GCHeapCount","System.GC.HeapCount",0,"Specfies the number of server GC heaps")

我们需要为某个应用程序指定12个堆,可以如下设置:

SET DOTNET_GCHeapCount=0xC

它的DOTNET_前缀添加的是配置文件的第二项,这点需要注意。

下面看下DATAS的实际上的某一个应用,如何控制大对象的压缩:

HRESULT gc_heap::initialize_gc (size_t soh_segment_size,
                                size_t loh_segment_size,
                                size_t poh_segment_size
#ifdef MULTIPLE_HEAPS
                                ,int number_of_heaps
#endif //MULTIPLE_HEAPS
)
{
   #ifdef DYNAMIC_HEAP_COUNT
    dynamic_adaptation_mode = (int)GCConfig::GetGCDynamicAdaptationMode();
    if (GCConfig::GetHeapCount() != 0)
    {
        dynamic_adaptation_mode = 0;
    }


    if ((dynamic_adaptation_mode == dynamic_adaptation_to_application_sizes) && (conserve_mem_setting == 0))
        conserve_mem_setting = 5;
#endif //DYNAMIC_HEAP_COUNT
}

当在进行GC初始化的时候,获取到DATAS的默认值(9 PreView7默认开启为1),如果同时设置了GC_Heap,则可以通过相应的dynamic_adaptation_mode值设置conserve_mem_setting 。conserve_mem_setting 干嘛的呢?它是计算碎片的空间大小,以及标记大对象堆是否压缩。

if ((conserve_mem_setting != 0) && (n == max_generation))
    {
        float frag_limit = 1.0f - conserve_mem_setting / 10.0f;


        size_t loh_size = get_total_gen_size (loh_generation);
        size_t gen2_size = get_total_gen_size (max_generation);
        float loh_frag_ratio = 0.0f;
        float combined_frag_ratio = 0.0f;
        if (loh_size != 0)
        {
            size_t loh_frag  = get_total_gen_fragmentation (loh_generation);
            size_t gen2_frag = get_total_gen_fragmentation (max_generation);
            loh_frag_ratio = (float)loh_frag / (float)loh_size;
            combined_frag_ratio = (float)(gen2_frag + loh_frag) / (float)(gen2_size + loh_size);
        }
        if (combined_frag_ratio > frag_limit)
        {
            dprintf (GTC_LOG, ("combined frag: %f > limit %f, loh frag: %f", combined_frag_ratio, frag_limit, loh_frag_ratio));
            gc_data_global.gen_to_condemn_reasons.set_condition (gen_max_high_frag_p);


            n = max_generation;
            *blocking_collection_p = TRUE;
            if (loh_frag_ratio > frag_limit)
            {
                settings.loh_compaction = TRUE;


                dprintf (GTC_LOG, ("compacting LOH due to GCConserveMem setting"));
            }
        }
    }

我们可以通过中文描述下上面的代码,如果通过DATAS设置的conserve_mem_setting 不为零,且当前回收代是2代(比如GC.Collect()),那么有以下计算公式

如果大对象堆!=0
{
   大对象堆碎片率=大对象堆的碎片大小/大对象堆的总大小;
   大对象和二代碎片率=(大对象堆碎片大小+二代堆碎片大小)/(大对象堆大小+二代堆大小); 
}
如果(大对象和二代碎片率>(1.0f - conserve_mem_setting / 10.0f))&&(大对象堆碎片率>(1.0f - conserve_mem_setting / 10.0f)) 
{
   标记大对象堆可以进行压缩了;
}

这是一个基本原理用法的地方,还有很多地方的此种类型设置堆GC进行丝滑控制,以达到动态SVR GC堆的目的。

结尾

.NET9 PreView7里面引入的DATAS,在很久之前就已经进行了实验。本篇简略分析下,实际上GC运行过程非常复杂。

往期精彩回顾

.NET9 Pre3 CLR的优化细节

.NET9异常(CLR)原理(顶阶技术

965e76de8f95eb5f795048f0c33762b7.jpeg

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值