.NET Core 配置GC工作模式与内存的影响

对GC工作模式的分类

为了满足不同的内存使用要求,GC 有一些选项来配置其运行方式。有两种主要模式:工作站模式(旨在最小化延迟)和服务器模式(旨在最大应用程序吞吐量)。GC 还支持两种“子模式”之一——并发或非并发

  • 工作站模式
  • 服务器模式
  • 并发垃圾回收(.NET Framework 4以上被后台垃圾回收代替)
  • 非并发垃圾回收(.NET Framework 4以上被后台垃圾回收代替)
  • 后台垃圾回收(后台垃圾回收期间对暂时代(0,1代)的回收称为“前台”垃圾回收, 后台垃圾回收是在一个或多个专用线程上执行的,具体取决于它是工作站还是服务器 GC,它只适用于第 2 代回收)

工作模式工作站服务器
工作方式后台非并发

GC内存分配原则

暂时代:因为第 0 代和第 1 代中的对象的生存期较短,因此,这些代被称为“暂时代”。

暂时段:暂时代在称为“暂时段(段:Segment)”的内存段中进行分配。 垃圾回收器获取的每个新段将成为新的暂时段,并包含在第 0 代垃圾回收中幸存的对象。 旧的暂时段将成为新的第 2 代段。

第 2 代段:保存第二代对象(大对象 以及暂时代的幸存对象)的内存段。

根据系统为 32 位还是 64 位以及它正在哪种类型的垃圾回收器(工作站或服务器 GC)上运行,暂时段的大小发生相应变化。 下表显示了暂时段的默认大小。

Segment的大小取决于系统是32位还是64位,以及它正在运行的垃圾收集器的类型,下表列出了分配时系统所使用的默认值:

GC 类型 32-bit 64-bit
Workstation(工作站) GC 16 MB 256 MB
Server GC(服务器) 64 MB 4 GB
Server GC with > 4 logical(逻辑) CPUs 32 MB 2 GB
Server GC with > 8 logical(逻辑) CPUs 16 MB 1 GB

从以上表格可知: 工作站GC使用较小的Segment,服务器GC使用较大的Segment

工作站 GC 与服务器 GC

工作站 GC 专为桌面应用程序而设计,可最大程度地减少 GC 所花费的时间。在这种情况下,GC 会更频繁地发生,但应用程序线程中的暂停时间会更短。该模式支持 并发非并发 两种执行模式(并发执行模式为默认的执行模式, netcore中被"后台GC"代替),一般适用于客户端程序

服务器 GC 针对应用程序吞吐量进行了优化,有利于更长的 GC 暂停。内存消耗会更高,但应用程序可以处理更大量的数据而不触发垃圾收集。在netcore中也分为后台/前台GC

GC 类型 GC频率 GC使用线程 GC使用线程数
工作站GC 频繁 分配对象的线程 单线程
服务器GC 不频繁 独立线程 多线程

“并发”或“非并发”等 GC 风格可能有助于微调垃圾收集,以获得应用程序的最大性能和/或响应能力。并发模式减少了 GC 所花费的总时间,因为第二代的标记阶段发生在与应用程序线程并行的专用线程中。在此模式下,GC 会暂停用户线程较短的时间,但会使用稍多的内存。

用于垃圾回收的运行时配置选项

详细的设置, 参考微软官方文档: https://learn.microsoft.com/zh-cn/dotnet/core/runtime-config/garbage-collector

# runtimeconfig.json
{
   "runtimeOptions": {
      "configProperties": {
         "System.GC.Server": true, # 工作站false, 服务器true
         "System.GC.Concurrent": false # 非并发false, 后台(并发)true
      }
   }
}
# MSBuild 属性
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <ServerGarbageCollection>true</ServerGarbageCollection> # 工作站false, 服务器true
    <ConcurrentGarbageCollection>false</ConcurrentGarbageCollection> # 非并发false, 后台(并发)true
  </PropertyGroup>
</Project>

工作站GC

工作站垃圾回收的线程处理和性能注意事项:

  • 回收发生在触发垃圾回收的用户线程上,并保留相同优先级。 因为用户线程通常以普通优先级运行,所以垃圾回收器(在普通优先级线程上运行)必须与其他线程竞争 CPU 时间。 (运行本机代码的线程不会由于服务器或工作站垃圾回收而挂起。)

  • 工作站垃圾回收始终用于只有一个逻辑 CPU 的计算机,无论配置设置如何。

服务器GC

从 .NET Framework 4.5 开始,或.net core中,后台垃圾回收可用于服务器 GC。 服务器 GC 是服务器垃圾回收的默认模式。

服务器 GC 以内存换取吞吐量。较大的堆意味着内存饱和发生的频率较低,但一旦发生,CLR 需要做更多的工作来遍历堆。因此,应用程序会消耗更多的内存,GC 发生的频率会降低,但即使是收集 Gen0 和 Gen1,每次 GC 也会花费更长的时间。

服务器垃圾回收的线程处理和性能注意事项

  • 回收发生在多个专用线程上。 在 Windows 上,这些线程以 THREAD_PRIORITY_HIGHEST 优先级运行。

  • 每个逻辑 CPU 提供一个用于执行垃圾回收的一个堆和专用线程,并将同时回收这些堆。 每个堆都包含一个小对象堆和一个大对象堆,并且所有的堆都可由用户代码访问。 不同堆上的对象可以相互引用。

  • 因为多个垃圾回收线程一起工作,所以对于相同大小的堆,服务器垃圾回收比工作站垃圾回收更快一些

  • 服务器垃圾回收通常具有更大的段。 但是,这是通常情况:段大小特定于实现且可能更改。 调整应用程序时,不要假设垃圾回收器分配的段大小。

  • 服务器垃圾回收会占用大量资源。 例如,假设在一台有 4 个逻辑 CPU 的计算机上,运行着 12 个使用服务器 GC 的进程。 如果所有进程碰巧同时回收垃圾,它们会相互干扰,因为将在同一个逻辑 CPU 上调度 12 个线程。 如果进程处于活动状态,则最好不要让它们都使用服务器 GC。如果运行应用程序的数百个实例,请考虑使用工作站垃圾回收并禁用并发垃圾回收。 这可以减少上下文切换,从而提高性能。

后台服务器垃圾回收后台工作站垃圾回收具有类似功能,但有一些不同之处:

  • 后台工作站垃圾回收使用一个专用的后台垃圾回收线程,而后台服务器垃圾回收使用多个线程。 通常一个逻辑处理器有一个专用线程。
  • 不同于工作站后台垃圾回收线程,这些后台服务器 GC 线程不会超时

常用GC相关的方法和设置

GCSettings.LargeObjectHeapCompactionMode

CompactOnce 下一次阻止第 2 代垃圾回收期间将压缩大型对象堆 (LOH)。
Default 不压缩大型对象堆 (LOH)。

// 指定是否对大对象堆进行压缩,以减少内存碎片
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;

GCSettings.LatencyMode

参考官方文档

https://learn.microsoft.com/zh-cn/dotnet/api/system.runtime.gclatencymode?view=net-7.0
https://learn.microsoft.com/zh-cn/dotnet/standard/garbage-collection/latency

// 控制GC的延迟模式,以平衡系统的响应性能和内存使用
GCSettings.LatencyMode = GCLatencyMode.SustainedLowLatency;

GC.WaitForPendingFinalizers

挂起当前线程,直到处理终结器队列的线程清空该队列为止。

https://learn.microsoft.com/zh-cn/dotnet/api/system.gc.waitforpendingfinalizers?view=net-7.0

// 等待待定的Finalizer方法执行完毕
GC.WaitForPendingFinalizers();
using System.Runtime;
//查看GC的初始配置:类型、工作方式以及微调工作方式。  类型、工作方式在.json或xml文件中修改。不过可用在程序运行时候微调
Console.WriteLine($"IsServerGC:{GCSettings.IsServerGC}");// 是否是服务器GC
Console.WriteLine($"IsConcurrent:{System.GC.GetGCMemoryInfo().Concurrent}");//工作方式 System.GC  
Console.WriteLine($"LatencyMode:{GCSettings.LatencyMode}");// 微调工作方式状态

扩展阅读

微软官方文档:垃圾回收
.NET 运行时配置设置
【CLR C#】浅谈.Net的GC(垃圾回收)机制及其整体流程
.NET Core 配置GC工作模式与内存的影响
了解不同的 GC 模式
编写高性能.net代码--垃圾回收的前世今生

此处评论已关闭