Maoni Stephens 是 .NET 垃圾回收器 (GC) 的首席架构师之一,她在2023年8月份发表了一篇关于 .NET GC 新功能的博客文章,该功能称为 Dynamic Adaption To Application Sizes (DATAS),该功能将随 .NET 8 一起提供。此功能将在应用运行时自动增加或减少服务器 GC 模式下的托管堆数量。它减少了 .NET 应用使用的内存总量,使服务器 GC 模式成为内存受限环境(如 Docker 容器或 Kubernetes Pod)的可行选项,这些环境可以访问多个逻辑 CPU 内核。

服务器 GC 模式和工作站 GC 模式之间的差异

工作站模式最初是为客户端应用程序设计的。过去,执行应用代码的线程会停止,直到 GC 运行完成。在桌面应用程序中,您不希望在几毫秒甚至几秒钟内出现冻结,因此 Workstation GC 经过调整,可以更频繁地执行运行,并更快地完成单个运行。从 .NET Framework 4.0 开始,我们还具有后台 GC 运行模式,可最大程度地减少线程被阻塞的时间。

相比之下,服务器 GC 旨在最大限度地提高服务的吞吐量,这些服务将随着时间的推移接收短期请求。GC 运行频率较低,但可能需要更长的时间。最后,您将在 GC 上运行上花费更少的时间,而将更多的时间花在服务代码上。

最明显的区别如下:Workstation GC 仅使用单个托管堆。托管堆由以下子堆组成:

  • 小对象堆 (SOH) 及其三代 0、1 和 2。小于 85,000 字节的对象将在此处分配。
  • 大型对象堆 (LOH),用于大于或等于 85,000 字节的对象。
  • 固定对象堆 (POH),主要由为此执行互操作和固定缓冲区的库使用(例如,用于网络或其他 I/O 方案)。

在服务器 GC 模式下,您将拥有多个这样的托管堆,默认情况下每个逻辑 CPU 内核一个,但这可以通过 GCHeapCount 进行调整。

托管堆数量增加,以及 GC 运行执行频率较低,是解释为什么服务器 GC 模式下内存消耗要高得多的重要因素。

但是,如果您希望从服务器 GC 模式中受益,同时在运行时动态调整托管堆的数量,该怎么办?一个典型的方案是在云中运行的服务,它必须在特定的突发时间处理大量请求,但之后它应该缩减以减少内存消耗。到目前为止,除了使用不同的配置值重新启动服务外,您没有办法实现这一点。纵向扩展也需要重新启动,因此许多开发团队只是试图通过 GCHeapCountConserveMemory 选项找到折衷方案。

这时,.NET 8 带来了一项名为“动态适应应用程序大小”(DATAS) 的新功能就派上用场了。DATAS 在运行时将按以下方式运行:

  1. GC 将仅从单个托管堆开始。
  2. 根据称为“吞吐量成本百分比”的指标,GC 将决定增加托管堆的数量是否可行。这将在每三次 GC 运行时进行评估。
  3. 还有一个称为“空间成本”的指标,GC 使用它来决定是否应该减少托管堆的数量。
  4. 如果 GC 决定增加或减少托管堆的数量,它将阻塞您的线程(类似于压缩 GC 运行)并创建或删除托管堆。相应的内存区域将被移动。当涉及到托管堆中内存的内部组织时,在 .NET 6 和 .NET 7 中从段切换到区域,使此方案成为可能。

优点和缺点?

DATAS 允许在内存受限环境中使用服务器 GC 模式,例如在 Docker 容器、Kubernetes Pod 。在您的服务将受到大量请求的攻击突发期间,GC 将动态增加托管堆的数量,以便从服务器 GC 的优化吞吐量设置中受益。突发结束后,GC 将再次减少托管堆的数量,从而减少应用使用的内存总量。即使在突发期间,GC 也可能选择将托管堆增加到每个逻辑 CPU 内核少于 1 个,因此您最终可能会使用更少的内存,而无需手动配置托管堆的数量。

请记住:当应用只有一个逻辑 CPU 内核可用时,应始终使用 Workstation GC 模式。仅当应用有两个或更多可用内核时,服务器 GC 模式才有用。此外,我建议您验证您是否确实需要服务器 GC 模式。使用 K6NBomber 等工具来衡量 Web 应用的吞吐量。如果仔细设计了应用的内存使用情况,则吞吐量可能根本没有差异。永远记住:.NET GC 只会在分配内存时执行其运行。

DATAS 是一项很棒的新功能,它将 Workstation GC 和 Server GC 的优势结合在一起:您开始时内存更少,当请求激增时,GC 可以动态扩展其托管堆的数量以提高吞吐量。当请求数在以后的某个时间点减少时,也可以减少托管堆的数量以释放内存。

DATAS 可以在.NET 8 产品中使用,但是并没有默认启用,需要手动进行指定:若要试用 DATAS,需要安装 .NET 8 SDK,创建一个 .NET 8 应用(例如 ASP.NET Core),然后可以将以下两行添加到 .csproj 文件:

<PropertyGroup>
     <ServerGarbageCollection>true</ServerGarbageCollection>
     <GarbageCollectionAdapatationMode>1</GarbageCollectionAdapatationMode>

</PropertyGroup>

您还可以在构建项目时通过命令行参数指定它:

dotnet build /p:ServerGarbageCollection=true /p:GarbageCollectionAdapatationMode=1

或者在 runtimeconfig.json 中:

"configProperties": {
     "System.GC.Server": true,
     "System.GC.DynamicAdaptationMode": 1

}

或者通过环境变量:

set DOTNET_gcServer=1

set DOTNET_GCDynamicAdaptationMode=1

请记住:使用上述方法之一时,不得设置 GCHeapCount 选项。如果这样做,GC 将只使用指定数量的堆,而不会激活 DATAS。同样重要的是:如果要在工作站模式下运行,只需将 ServerGarbageCollection 或相应的配置属性/环境变量分别设置为 false 或零。

默认情况下,我的 ASP.NET Core 应用将使用哪种 GC 模式?

你的 ASP.NET Core 应用可以访问多少个逻辑 CPU 内核?如果小于两个,则将使用 Workstation GC 模式。否则,默认情况下将激活服务器 GC 模式。因此,在 Docker、Kubernetes 或云环境中为应用指定约束时要特别小心,因为这些环境可能会突然进入另一个 GC 模式,占用的内存比预期的要多。

ASP.NET Core 8 的内存占用可以更低吗?的更多相关文章

  1. ASP.NET Core - 缓存之内存缓存(上)

    1. 缓存 缓存指的是在软件应用运行过程中,将一些数据生成副本直接进行存取,而不是从原始源(数据库,业务逻辑计算等)读取数据,减少生成内容所需的工作,从而显著提高应用的性能和可伸缩性,使用好缓存技术, ...

  2. ASP.NET Core - 缓存之内存缓存(下)

    话接上篇 [ASP.NET Core - 缓存之内存缓存(上)],所以这里的目录从 2.4 开始. 2.4 MemoryCacheEntryOptions MemoryCacheEntryOption ...

  3. asp.net core webapi Session 内存缓存

    Startup.cs文件中的ConfigureServices方法配置: #region Session内存缓存 services.Configure<CookiePolicyOptions&g ...

  4. 在ASP.NET Core 2.0中使用MemoryCache

    说到内存缓存大家可能立马想到了HttpRuntime.Cache,它位于System.Web命名空间下,但是在ASP.NET Core中System.Web已经不复存在.今儿个就简单的聊聊如何在ASP ...

  5. 为什么我的会话状态在ASP.NET Core中不工作了?

    原文:Why isn't my session state working in ASP.NET Core? Session state, GDPR, and non-essential cookie ...

  6. asp.net core 缓存和Session

    缓存 缓存在内存中 ASP.NET Core 使用 IMemoryCache内存中缓存是使用依赖关系注入从应用中引用的服务. 请在ConfigureServices中调用AddMemoryCache( ...

  7. ASP.Net Core使用分布式缓存Redis从入门到实战演练

    一.课程介绍 人生苦短,我用.NET Core!缓存在很多情况下需要用到,合理利用缓存可以一方面可以提高程序的响应速度,同时可以减少对特定资源访问的压力.  所以经常要用到且不会频繁改变且被用户共享的 ...

  8. ASP.NET Core - 缓存之分布式缓存

    分布式缓存是由多个应用服务器共享的缓存,通常作为访问它的应用服务器的外部服务进行维护. 分布式缓存可以提高 ASP.NET Core 应用的性能和可伸缩性,尤其是当应用由云服务或服务器场托管时. 与其 ...

  9. ASP.NET Core 1.0 静态文件、路由、自定义中间件、身份验证简介

    概述 ASP.NET Core 1.0是ASP.NET的一个重要的重新设计. 例如,在ASP.NET Core中,使用Middleware编写请求管道. ASP.NET Core中间件对HttpCon ...

  10. ASP.NET Core 源码学习之 Logging[1]:Introduction

    在ASP.NET 4.X中,我们通常使用 log4net, NLog 等来记录日志,但是当我们引用的一些第三方类库使用不同的日志框架时,就比较混乱了.而在 ASP.Net Core 中内置了日志系统, ...

随机推荐

  1. excel的烦恼

    Smiling & Weeping ---- 他未对我好半分,偏巧这感情疯长似野草 题目链接:https://www.matiji.net 思路:与新三进制2思路相似,转化为纯26进制,然后往 ...

  2. Mac SpringBoot项目 Gradle 7.3 转 Maven 手把手教学,包学会~

    导读 最近我手上有个使用Gradle构建的项目,国内使用Gradle的人相对较少.而且我也觉得Gradle的依赖管理方式有些复杂,让我感到有些困惑.因此,我想将项目转换为Maven构建方式.Maven ...

  3. SQL Server查询数据库中的表

    SQL Server查询数据库中的表 SSMS中用不了MySQL中的show 查询当前数据库中所有表名: SELECT name FROM sysobjects WHERE (xtype = 'U') ...

  4. Github的一个奇技淫巧

    背景 前段时间给 VictoriaLogs 提交了一个 PR: https://github.com/VictoriaMetrics/VictoriaMetrics/pull/4934 本来一切都很顺 ...

  5. Redis和Memcache区别,优缺点对比(转)

    转自 https://www.cnblogs.com/JavaBlackHole/p/7726195.html 1. Redis和Memcache都是将数据存放在内存中,都是内存数据库.不过memca ...

  6. 从原理到实战,详解XXE攻击

    本文分享自华为云社区<[安全攻防]深入浅出实战系列专题-XXE攻击>,作者: MDKing. 1 基本概念 XML基础:XML 指可扩展标记语言(Extensible Markup Lan ...

  7. 2023-10-25:用go语言,假如某公司目前推出了N个在售的金融产品(1<=N<=100) 对于张三,用ai表示他购买了ai(0<=ai<=10^4)份额的第i个产品(1<=i<=N) 现给出K(

    2023-10-25:用go语言,假如某公司目前推出了N个在售的金融产品(1<=N<=100) 对于张三,用ai表示他购买了ai(0<=ai<=10^4)份额的第i个产品(1& ...

  8. Docker磁盘&内存&CPU资源实战

    Docker 资源实战:cpu/内存配置: #查看帮助 docker run --help docker update --help #配置容器使用cpu /内存大小--privileged 给与容器 ...

  9. unity2017自定义编译dll

    适用于自定义编译平台和编译符合,把C#源码文件编译成dll.(用于InjectFix之类的热更方案) 适用于unity2017环境,代码暂时不方便贴出记述一下思路. 参考:Unity官方C#源码 ht ...

  10. 字符串匹配|kmp笔记

    很久之前学的了. 我很懒,不太喜欢画图. 做个笔记回忆一下: kmp 朴素比对字符串 所谓字符串匹配,是这样一种问题:"字符串 T 是否为字符串 S 的子串?如果是,它出现在 S 的哪些位置 ...