Skip to content

Change in GC behavior in 8.0.17 #117319

@KeterSCP

Description

@KeterSCP

Description

Starting from 8.0.17 runtime version, GC does not return unmanaged memory to the OS on forced full GC.

Suspected change is #115023
Related: #108081

Reproduction Steps

  1. Make sure you have both 8.0.16 and 8.0.17 runtimes installed, 8.0.410 and 8.0.411 respective versions of SDK

  2. Program.csproj:

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net8.0</TargetFramework>
        <RollForward>Disable</RollForward>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <ServerGarbageCollection>true</ServerGarbageCollection>
    </PropertyGroup>
</Project>
  1. Program.cs:
using System.Diagnostics;
using System.Runtime.CompilerServices;

Console.WriteLine(Environment.Version);

for (int i = 0; i < 10; i++)
{
    _ = Allocate();
}

Console.WriteLine($"Private memory before GC: {GetPrivateMemoryMb()} MB");
TriggerGc(); // No matter how many times you call this, process private memory stays the same on 8.0.17
Console.WriteLine($"Private memory after GC: {GetPrivateMemoryMb()} MB");

[MethodImpl(MethodImplOptions.NoInlining)]
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();
    Thread.Sleep(1000);
}

double GetPrivateMemoryMb()
{
    using var process = Process.GetCurrentProcess();
    var mb = process.PrivateMemorySize64 / 1024.0 / 1024.0;
    return Math.Round(mb, 2);
}
  1. Run dotnet clean -c Release && dotnet run -c Release -p:RuntimeFrameworkVersion='8.0.16'

  2. Run dotnet clean -c Release && dotnet run -c Release -p:RuntimeFrameworkVersion='8.0.17'

Expected behavior

Behavior should not change between patch versions of runtime, and preferably, GC should return memory to the OS on forced compacting GC.

Actual behavior

8.0.16
Private memory before GC: 9614.54 MB
Private memory after GC: 60.44 MB
8.0.17
Private memory before GC: 9614.56 MB
Private memory after GC: 9615.96 MB

Regression?

Yes. Regression from 8.0.16

Known Workarounds

  • Use 8.0.16 runtime version

Configuration

OS: Windows 11
Architecture: x64

Other information

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status

    No status

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions