后台 service/worker 不进行垃圾收集
Background service/worker don't garbage collect
我需要一个 IHostedService,或“Worker Service”,但我遇到了一个有趣的难题,那就是垃圾收集器不会 运行 在“适当的”时间。相反,它只是不收集任何资源,导致应用程序的内存使用量增加,(在调试期间,根本没有发生 GC)。
我已经完成了所有可以想到的事情,包括让我的所有任务 return 都具有一定的价值,并尽可能使用 using 语句。还使用依赖注入抽象了一些层,(以确保有多个地方应该与运行时间通信,它适合运行垃圾收集。
我唯一的“解决方案”(不是解决方案)是手动 运行 GC.Collect();
namespace Worker
{
public class Worker : BackgroundService
{
private readonly ILogger<Worker> _logger;
public Worker(ILogger<Worker> logger)
{
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation($"Worker running at: {DateTime.Now}");
var files = Directory.EnumerateFiles(@"C:\repos\");
var date = files.Select(f => File.ReadAllBytesAsync(f));
GC.Collect();
}
}
}
}
结果是我的代码在没有手动触发 GC 的情况下会膨胀以最大化可用内存,但是,使用手动 GC 这可以 运行 数小时而资源使用情况没有明显变化
解决方案
使用本文中提到的设置:https://dotnet.github.io/orleans/1.5/Documentation/Deployment-and-Operations/Configuration-Guide/Configuring-.NET-Garbage-Collection.html(已弃用)
已更新 link:https://docs.microsoft.com/en-us/dotnet/core/run-time-config/garbage-collector
这是服务器 GC 的预期行为。它经过调整以充分利用可用内存,因此除非确实需要,否则不会收集。这真的是问题吗? OS 能够根据需要调入和调出内存,因此如果您使用的是 64 位 运行,则在大多数情况下应该不会产生影响。如果这仍然是一个问题,还有一些替代方案:
- 最简单的解决方案是切换到工作站 GC,它方式 更积极,并且会定期自动收集内存。将
gcServer
setting 设置为 false
将激活工作站 GC
- 你可以玩玩GC分配的堆数。如果 CPU 有大量核心,这会产生明显的影响。这可以使用
GCHeapCount
设置来完成。有关详细信息,请参阅来自 Maoni Stephens 的 this article
- 您可以创建 a Windows job 来限制进程可用的内存。然而,这要复杂得多,因为据我所知,Windows 中没有内置工具可以做到这一点
.NET Core 3.0 将带来新的设置以针对低内存场景调整 GC,但不会在第二学期之前发布。
我需要一个 IHostedService,或“Worker Service”,但我遇到了一个有趣的难题,那就是垃圾收集器不会 运行 在“适当的”时间。相反,它只是不收集任何资源,导致应用程序的内存使用量增加,(在调试期间,根本没有发生 GC)。
我已经完成了所有可以想到的事情,包括让我的所有任务 return 都具有一定的价值,并尽可能使用 using 语句。还使用依赖注入抽象了一些层,(以确保有多个地方应该与运行时间通信,它适合运行垃圾收集。
我唯一的“解决方案”(不是解决方案)是手动 运行 GC.Collect();
namespace Worker
{
public class Worker : BackgroundService
{
private readonly ILogger<Worker> _logger;
public Worker(ILogger<Worker> logger)
{
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation($"Worker running at: {DateTime.Now}");
var files = Directory.EnumerateFiles(@"C:\repos\");
var date = files.Select(f => File.ReadAllBytesAsync(f));
GC.Collect();
}
}
}
}
结果是我的代码在没有手动触发 GC 的情况下会膨胀以最大化可用内存,但是,使用手动 GC 这可以 运行 数小时而资源使用情况没有明显变化
解决方案 使用本文中提到的设置:https://dotnet.github.io/orleans/1.5/Documentation/Deployment-and-Operations/Configuration-Guide/Configuring-.NET-Garbage-Collection.html(已弃用)
已更新 link:https://docs.microsoft.com/en-us/dotnet/core/run-time-config/garbage-collector
这是服务器 GC 的预期行为。它经过调整以充分利用可用内存,因此除非确实需要,否则不会收集。这真的是问题吗? OS 能够根据需要调入和调出内存,因此如果您使用的是 64 位 运行,则在大多数情况下应该不会产生影响。如果这仍然是一个问题,还有一些替代方案:
- 最简单的解决方案是切换到工作站 GC,它方式 更积极,并且会定期自动收集内存。将
gcServer
setting 设置为false
将激活工作站 GC - 你可以玩玩GC分配的堆数。如果 CPU 有大量核心,这会产生明显的影响。这可以使用
GCHeapCount
设置来完成。有关详细信息,请参阅来自 Maoni Stephens 的 this article - 您可以创建 a Windows job 来限制进程可用的内存。然而,这要复杂得多,因为据我所知,Windows 中没有内置工具可以做到这一点
.NET Core 3.0 将带来新的设置以针对低内存场景调整 GC,但不会在第二学期之前发布。