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. mpi转以太网连接300PLC无需编程与1200PLC数据交换

    300PLC转以太网无需编程300PLC通过 NetDevice与1200PLC数据交换 应用概述: 兴达易控MPI转以太网模块MPI-ETH-XD1.0PLUS 通讯模块实现PLC无需编程通过简单的 ...

  2. Oracle CloudWorld 2023:Safra Catz主题演讲——把客户的成功放在首要位置

    Safra Catz在Oracle CloudWorld 2023的开场演讲主题是"把客户的成功放在首要位置".她强调了客户的重要性,并说大家通过合作和技术可以实现几乎一切.她感谢 ...

  3. 爬虫系列——selenium

    文章目录 一 介绍 二 安装 三 基本使用 四 选择器 五 等待元素被加载 六 元素交互操作 七 其他 八 项目练习 一 介绍 selenium最初是一个自动化测试工具,而爬虫中使用它主要是为了解决r ...

  4. Django CMS搭建--1.虚拟环境搭建

    客户端环境:windows10 1.virtualenv使用 virtualenv 是 Python 中的一个包,用于创建和管理虚拟环境,可以在不同的项目中使用不同的 Python 版本和第三方库,避 ...

  5. 常见的企业Wiki

    企业Wiki(Enterprise Wiki)指适用于企业或组织内部使用的Wiki.与非企业Wiki(如著名的MediaWiki)最根本的不同点在于,企业Wiki是为企业量身定做的Wiki.通过鼓励. ...

  6. 关于C++拷贝控制

    通常来说,对于类内动态分配资源的类需要进行拷贝控制:要在拷贝构造函数.拷贝赋值运算符.析构函数中实现安全高效的操作来管理内存.但是资源管理并不是一个类需要定义自己的拷贝控制成员的唯一原因.C++ Pr ...

  7. Flink测试利器之DataGen初探

    什么是 Flinksql Flink SQL 是基于 Apache Calcite 的 SQL 解析器和优化器构建的,支持ANSI SQL 标准,允许使用标准的 SQL 语句来处理流式和批处理数据.通 ...

  8. 服务器没有开放3306端口 远程访问MySQL数据库方法

    一.前言 ​ 当装有MySQL的服务器为了防止数据库被黑,提高安全性,把3306端口禁止掉,禁止对外访问,我之前写过一篇是借助跳板机的SSH隧道来访问实现安全,这种情况依然需要开放3306端口和使用一 ...

  9. 22. 从零用Rust编写正反向代理,一个数据包的神奇HTTP历险记!

    wmproxy wmproxy已用Rust实现http/https代理, socks5代理, 反向代理, 静态文件服务器,四层TCP/UDP转发,内网穿透,后续将实现websocket代理等,会将实现 ...

  10. USB TYPE-C PIN定义

    USB TYPE-C 母座 USB TYPE-C 公头