Merge pull request #645 from sp-tarkov/disable-gc-requests

Added NoGCRegion feature
This commit is contained in:
Chomp
2025-10-20 12:00:30 +00:00
committed by GitHub
4 changed files with 131 additions and 6 deletions
@@ -5,6 +5,9 @@
"profileSaveIntervalSeconds": 15,
"sptFriendNickname": "SPT",
"allowProfileWipe": true,
"enableNoGCRegions": true,
"noGCRegionMaxMemoryGB": 4,
"noGCRegionMaxLOHMemoryGB": 3,
"bsgLogging": {
"verbosity": 6,
"sendToServer": false
@@ -42,6 +42,50 @@ public record CoreConfig : BaseConfig
[JsonPropertyName("features")]
public required ServerFeatures Features { get; set; }
[JsonPropertyName("enableNoGCRegions")]
// ReSharper disable once InconsistentNaming
public required bool EnableNoGCRegions { get; set; }
// ReSharper disable once InconsistentNaming
private int _noGCRegionMaxMemoryGB = 4;
[JsonPropertyName("noGCRegionMaxMemoryGB")]
// ReSharper disable once InconsistentNaming
public required int NoGCRegionMaxMemoryGB
{
get => _noGCRegionMaxMemoryGB;
set
{
if (value <= 0)
{
throw new ArgumentOutOfRangeException(
$"Invalid value: {nameof(NoGCRegionMaxMemoryGB)}: {value}. Must be greater than zero."
);
}
_noGCRegionMaxMemoryGB = value;
}
}
// ReSharper disable once InconsistentNaming
private int _noGCRegionMaxLOHMemoryGB = 3;
[JsonPropertyName("noGCRegionMaxLOHMemoryGB")]
// ReSharper disable once InconsistentNaming
public required int NoGCRegionMaxLOHMemoryGB
{
get => _noGCRegionMaxLOHMemoryGB;
set
{
if (value <= 0)
{
throw new ArgumentOutOfRangeException(
$"Invalid value {nameof(NoGCRegionMaxLOHMemoryGB)}: {value}. Must be greater than zero."
);
}
_noGCRegionMaxLOHMemoryGB = value;
}
}
/// <summary>
/// Commit hash build server was created from
/// </summary>
+4 -6
View File
@@ -1,5 +1,6 @@
using System.Net;
using System.Net.Sockets;
using System.Runtime;
using System.Runtime.InteropServices;
using System.Security.Authentication;
using System.Text;
@@ -147,12 +148,9 @@ public static class Program
app.UseMiddleware<SptLoggerMiddleware>();
app.Use(
async (HttpContext context, RequestDelegate next) =>
{
await context.RequestServices.GetRequiredService<HttpServer>().HandleRequest(context, next);
}
);
app.UseNoGCRegions();
app.Use(async (context, next) => await context.RequestServices.GetRequiredService<HttpServer>().HandleRequest(context, next));
app.UseSptBlazor();
}
@@ -0,0 +1,80 @@
using System.Runtime;
using SPTarkov.Server.Core.Models.Spt.Config;
using SPTarkov.Server.Core.Servers;
namespace SPTarkov.Server.Services;
// ReSharper disable once InconsistentNaming
public class NoGCRegionMiddleware(RequestDelegate next)
{
private static long _activeRequests;
private static bool OtherRequestsActive
{
get
{
return Interlocked.Read(ref _activeRequests) > 1;
}
}
public async Task InvokeAsync(HttpContext context)
{
Interlocked.Increment(ref _activeRequests);
var config = context.RequestServices.GetRequiredService<ConfigServer>().GetConfig<CoreConfig>();
// if no other requests are running, start the no GC region, otherwise dont start it
if (!OtherRequestsActive)
{
if (config.EnableNoGCRegions && GCSettings.LatencyMode != GCLatencyMode.NoGCRegion)
{
try
{
GC.TryStartNoGCRegion(
1024L * 1024L * 1024L * config.NoGCRegionMaxMemoryGB,
1024L * 1024L * 1024L * config.NoGCRegionMaxLOHMemoryGB,
true
);
}
catch (Exception)
{
// ignored, we keep going
}
}
}
try
{
await next(context);
}
finally
{
Interlocked.Decrement(ref _activeRequests);
}
// if no other requests are running, end the no GC region, otherwise dont stop it as other requests need it still
if (!OtherRequestsActive)
{
if (config.EnableNoGCRegions && GCSettings.LatencyMode == GCLatencyMode.NoGCRegion)
{
try
{
GC.EndNoGCRegion();
}
catch (Exception)
{
// ignored, we dont care about handling this
}
}
}
}
}
// ReSharper disable once InconsistentNaming
public static class NoGCRegionMiddlewareExtensions
{
// ReSharper disable once InconsistentNaming
public static IApplicationBuilder UseNoGCRegions(this IApplicationBuilder builder)
{
return builder.UseMiddleware<NoGCRegionMiddleware>();
}
}