Skip to content

文章

.Net Core 中的垃圾回收类型

2019年9月2日 • 7 分钟阅读

.Net Core 中的垃圾回收类型

现代编程语言中的内存管理往往是事后考虑的问题。从各种意图和目的来看,我们编写软件时几乎不会考虑内存问题。这对我们很有帮助,但总有例外情况…

在加利福尼亚州,地方教育机构(LEA)有广泛的财务报告要求,LEA 可以是县、学区、特许学校或单一学校。大多数 LEA 创建自己的财务报告,通常以 Excel 为中心,当每个报告都不同时也就不足为奇了。为了解决这个问题,加利福尼亚州教育委员会委托开发软件来生成财务报告。

我是开发团队的一员。

我的第一站是测试日志,Ed-Pro 的日志指向高内存使用率,也许存在内存泄漏?一位工程师观察到 Ed-Pro 的计算使用了大量短期内存。如果内存没有快速清理,可能看起来像内存泄漏。

Ed-Pro 构建在 .Net Core 之上,这是微软的多平台框架。在 .Net Core 中,内存分为三个标签:短期(Gen0)、中期(Gen1)和长期(Gen2)。Gen0 用于快速超出作用域的短期数据,Gen1 用于持续时间稍长的中期内存,它最终也会超出作用域,Gen2 是可能在应用程序生命周期内存在的长期内存。Gen0 内存不断被回收,Gen1 的回收频率低于 Gen0,Gen2 的回收频率甚至低于 Gen1。

了解 Ed-Pro 内存使用情况的唯一可靠方法是对其进行分析,下面是使用 JetBrains 的 dotMemory 的截图。

正如预期的那样,我们发现了大量的 Gen0 内存(蓝色部分),如此之多,以至于垃圾回收似乎跟不上。为了补偿大量内存而采用的策略,导致垃圾回收在增加内存空间(为应用程序使用添加更多内存)和清理内存之间振荡。在清理周期中,应用程序无响应。

起初,我们很困惑,GC 的目的不是保持内存整洁吗?两篇文章对我们理解 .Net 中垃圾回收的工作原理起到了重要作用:Mark Vincze 的文章在 Kubernetes 上排查 ASP.Net Core 高内存使用问题微软垃圾回收基础知识。两篇都是很好的读物,为 Ed-Pro 中的内存使用带来了清晰的理解。

以下是我们学到的总结,.Net 中有两种类型的垃圾回收:服务器垃圾回收和工作站垃圾回收。

服务器垃圾回收做了几个假设:首先,有充足的可用内存,其次,处理器是多核且速度快。两者都可能是真的,但我们生活在虚拟机和 Docker 的世界中,更可能的是两个假设都是错误的。

服务器垃圾回收允许内存积累,在某个时候,它会做两件事之一:要么增加内存空间允许内存增长,要么释放孤立的内存。当它选择释放内存时,垃圾回收在高优先级线程上启动该过程。高优先级线程的优先级高于应用程序;如果机器速度快,清理不应该被注意到。但是,如果不是,它会导致应用程序暂停,直到清理完成。

工作站垃圾回收的操作方式不同。它在与应用程序相同优先级的线程上持续运行回收内存。这意味着它也在与应用程序竞争资源,这可能导致应用程序变慢。好处是应用程序的内存使用可以保持相当低,主要是当它使用大量 Gen0 时。

默认情况下,如果 .Net Core 检测到服务器,它会运行服务器垃圾回收类型,这就是我们应用程序的情况。要运行工作站垃圾回收类型,请将以下代码片段添加到您的项目文件中:

  <PropertyGroup> 
    <ServerGarbageCollection>false</ServerGarbageCollection>
  </PropertyGroup>

我们对 Ed-Pro 进行了这个配置更改,使用 dotMemory,我们在启用工作站垃圾回收的情况下分析了 Ed-Pro 的内存,并加载了与之前测试相同的屏幕。以下是结果:

内存使用显著减少。Gen0 分配几乎不存在。除了图表中的差异外,服务器垃圾回收的内存使用峰值为 1GB,而工作站垃圾回收的峰值大约为 200MB。

每个应用程序都不同。我们的应用程序使用了大量临时数据,因此使用了大量 Gen0 内存。您的应用程序可能利用更长期的内存,如 Gen1 或 Gen2,在这种情况下服务器垃圾回收非常有意义。我的建议是在不同条件下分析您的内存,了解内存是如何使用的,然后决定哪种模式最适合您的应用程序。

作者:Chuck Conway 专注于软件工程和生成式人工智能。在社交媒体上与他联系:X (@chuckconway) 或访问他的 YouTube

↑ 回到顶部

您可能还喜欢