-
I have following test console app: .csproj: <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
</Project> Program.cs: using System.Diagnostics;
for (int i = 0; i < 10; i++)
{
_ = Allocate();
}
Console.WriteLine($"Private memory before GC: {GetPrivateMemoryMb()} MB");
TriggerGc();
Thread.Sleep(1000);
Console.WriteLine($"Private memory after GC: {GetPrivateMemoryMb()} MB");
int Allocate()
{
var data = new byte[1_000_000_000];
return data.Length;
}
void TriggerGc()
{
GC.Collect(generation: 2, GCCollectionMode.Forced, blocking: true, compacting: true);
GC.WaitForPendingFinalizers();
}
double GetPrivateMemoryMb()
{
using var process = Process.GetCurrentProcess();
var mb = process.PrivateMemorySize64 / 1024.0 / 1024.0;
return Math.Round(mb, 2);
} And here are tests for Server/WS GC: .NET 8 dotnet run -c Release -f net8.0 -p:ServerGarbageCollection=false
Private memory before GC: 1935.1 MB
Private memory after GC: 9.15 MB dotnet run -c Release -f net8.0 -p:ServerGarbageCollection=true
Private memory before GC: 9643.71 MB
Private memory after GC: 90.75 MB .NET 9 dotnet run -c Release -f net9.0 -p:ServerGarbageCollection=false
Private memory before GC: 1935.26 MB
Private memory after GC: 1935.44 MB dotnet run -c Release -f net9.0 -p:ServerGarbageCollection=true
Private memory before GC: 1956.43 MB
Private memory after GC: 1954.73 MB If I add two additional calls to GC.Collect: Console.WriteLine($"Private memory before GC: {GetPrivateMemoryMb()} MB");
TriggerGc();
+ TriggerGc();
+ TriggerGc();
Thread.Sleep(1000);
Console.WriteLine($"Private memory after GC: {GetPrivateMemoryMb()} MB"); .NET 9 shows following results: dotnet run -c Release -f net9.0 -p:ServerGarbageCollection=false
Private memory before GC: 1935.29 MB
Private memory after GC: 1935.53 MB dotnet run -c Release -f net9.0 -p:ServerGarbageCollection=true
Private memory before GC: 1956.41 MB
Private memory after GC: 28.62 MB My question is: what causes GC to return memory only on third call to GC.Collect, but not on first or second in .NET 9, and why workstation GC does not return memory to the OS at all regardless of the number of calls to GC.Collect? |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 1 reply
-
cc @dotnet/gc It seems like the behavior has changed between Preview7 (doesn't reproduce) and RC1 (reproduces), tested on Win-x64. Presumably, everything runs in Tier0 here so no method is inlined, hence, the array lives only within |
Beta Was this translation helpful? Give feedback.
-
sorry about that! this is caused by a change we checked in during RC1 and it was already reverted in RC2 with #107712. if you'd like to verify that it's fixed on RC2 that'd be great (I already verified on my end). |
Beta Was this translation helpful? Give feedback.
sorry about that! this is caused by a change we checked in during RC1 and it was already reverted in RC2 with #107712. if you'd like to verify that it's fixed on RC2 that'd be great (I already verified on my end).