gcsettings.latencymode 是 .net 的全局 gc 行为开关,用于调整回收激进程度,适用于游戏、音视频等低延迟场景;默认 interactive,sustainedlowlatency 替代已废弃的 lowlatency,需早期设置并主动管理 full gc,否则易 oom。

GCSettings.LatencyMode 是什么,什么时候该动它
GCSettings.LatencyMode 是 .NET 运行时提供的一个全局 GC 行为开关,它不改变内存分配逻辑,而是调整垃圾回收器的“激进程度”和响应节奏。它适用于对延迟敏感、且能预判内存压力周期的场景,比如游戏主循环、实时音视频处理、高频交易 tick 处理等。普通 Web API 或后台服务几乎不需要碰它——强行设错反而会让 GC 更频繁或更卡顿。
它的取值是 GCSettings.LatencyMode 枚举,常见选项有:GCLatencyMode.Interactive(默认)、GCLatencyMode.Batch、GCLatencyMode.LowLatency、GCLatencyMode.SustainedLowLatency。注意:.NET Core 3.0+ 和 .NET 5+ 中,LowLatency 已被标记为过时,推荐用 SustainedLowLatency 替代。
设置 SustainedLowLatency 模式的关键操作步骤
启用 GCLatencyMode.SustainedLowLatency 不是调个属性就完事,它要求你主动配合 GC 的节律:
- 必须在程序启动早期设置(例如
Main 方法开头),且只能设一次;后续再赋值会抛出 InvalidOperationException:“The latency mode cannot be changed after it has been set.”
- 设置后,GC 会大幅减少 full GC 触发频率,优先使用 gen0/gen1 回收,但堆内存可能持续增长——你得自己监控
GC.GetTotalMemory(false) 或通过 EventCounter 订阅 gc-heap-size
- 当检测到内存压力过高(例如物理内存占用超阈值、或触发
AppDomain.UnhandledException 前的临界点),应主动调用 GC.Collect(2, GCCollectionMode.Forced) + GC.WaitForPendingFinalizers(),否则可能 OOM
- 退出低延迟模式?不行。.NET 不提供重置接口,只能靠进程重启恢复默认行为
为什么 LowLatency 被废弃,SustainedLowLatency 又有什么不同
GCLatencyMode.LowLatency 在 .NET Core 2.x 中存在严重副作用:它会禁用 background GC,强制所有回收走 stop-the-world 路径,反而在大堆场景下导致更长暂停。而 SustainedLowLatency 是它的修正版——它仍禁用 background GC,但允许 gen0/gen1 在非阻塞路径上快速完成,并把 full GC 推迟到显式触发或系统内存严重不足时。
Main 方法开头),且只能设一次;后续再赋值会抛出 InvalidOperationException:“The latency mode cannot be changed after it has been set.”GC.GetTotalMemory(false) 或通过 EventCounter 订阅 gc-heap-size
AppDomain.UnhandledException 前的临界点),应主动调用 GC.Collect(2, GCCollectionMode.Forced) + GC.WaitForPendingFinalizers(),否则可能 OOMGCLatencyMode.LowLatency 在 .NET Core 2.x 中存在严重副作用:它会禁用 background GC,强制所有回收走 stop-the-world 路径,反而在大堆场景下导致更长暂停。而 SustainedLowLatency 是它的修正版——它仍禁用 background GC,但允许 gen0/gen1 在非阻塞路径上快速完成,并把 full GC 推迟到显式触发或系统内存严重不足时。
实际效果差异体现在:
– LowLatency:gen2 回收完全不可控,容易突然卡住 100ms+
– SustainedLowLatency:gen0 回收延迟稳定在 ~0.1ms 内,gen2 可控延后,但你必须自己守门
真实踩坑案例:Web API 里误开 SustainedLowLatency
某服务在 Startup 中写了 GCSettings.LatencyMode = GCLatencyMode.SustainedLowLatency,上线后前两小时正常,之后 RSS 持续上涨,K8s OOMKilled 频发。
- 根本原因:HTTP 请求生命周期短,对象大量进入 gen0,但因禁用 background GC,gen2 积压无法释放,
GC.GetTotalMemory(true) 显示托管堆达 2.4GB,而实际活跃对象仅 80MB
- 错误补救:加了定时
GC.Collect(2),但没加 GC.WaitForPendingFinalizers(),导致 finalizer 队列堆积,进一步拖慢吞吐
- 正确做法:去掉该设置;如真需控制延迟,改用
GC.TryStartNoGCRegion 包裹确定长度的热路径(例如单次图像处理),完成后立刻 GC.EndNoGCRegion()
别把它当成“让 GC 变快”的快捷键。它只是把 GC 的决策权从运行时移交给你——而你得真有能力判断“现在该不该收一次”。
GC.GetTotalMemory(true) 显示托管堆达 2.4GB,而实际活跃对象仅 80MBGC.Collect(2),但没加 GC.WaitForPendingFinalizers(),导致 finalizer 队列堆积,进一步拖慢吞吐GC.TryStartNoGCRegion 包裹确定长度的热路径(例如单次图像处理),完成后立刻 GC.EndNoGCRegion()










