Skip to content

Unexpected OOM with GCHeapLimit #94175

@kevingosse

Description

@kevingosse

Description

I run a code that allocates a 100MB array, iterates over it, then discard it (initially meant as a benchmark). When running with DOTNET_GCHeapHardLimit=7D000000, the code crashes at the 20th iteration with an OutOfMemoryException.

There are a number of things that make me think it's a bug:

  • It only happens with regions
  • It doesn't happen if I force a GC after each iteration
  • It doesn't happen if I increase the size of the array to be 150MB or bigger
  • When running with a debug CLR, it randomly triggers an assertion:
Assert failure(PID 30596 [0x00007784], Thread: 12248 [0x2fd8]): planned_regions_per_gen[0]
    File: E:\git\runtime\src\coreclr\gc\gc.cpp Line: 31714
    Image: E:\git\runtime\artifacts\bin\coreclr\windows.x64.Debug\corerun.exe


Assert failure(PID 30596 [0x00007784], Thread: 18508 [0x484c]): saved_planned_regions_per_gen[0] >= to_be_empty_regions
    File: E:\git\runtime\src\coreclr\gc\gc.cpp Line: 31721
    Image: E:\git\runtime\artifacts\bin\coreclr\windows.x64.Debug\corerun.exe


Assert failure(PID 30596 [0x00007784], Thread: 16148 [0x3f14]): saved_planned_regions_per_gen[0] >= to_be_empty_regions
    File: E:\git\runtime\src\coreclr\gc\gc.cpp Line: 31721
    Image: E:\git\runtime\artifacts\bin\coreclr\windows.x64.Debug\corerun.exe


Assert failure(PID 30596 [0x00007784], Thread: 16720 [0x4150]): saved_planned_regions_per_gen[0] >= to_be_empty_regions
    File: E:\git\runtime\src\coreclr\gc\gc.cpp Line: 31721
    Image: E:\git\runtime\artifacts\bin\coreclr\windows.x64.Debug\corerun.exe


Assert failure(PID 30596 [0x00007784], Thread: 17976 [0x4638]): saved_planned_regions_per_gen[0] >= to_be_empty_regions
    File: E:\git\runtime\src\coreclr\gc\gc.cpp Line: 31721
    Image: E:\git\runtime\artifacts\bin\coreclr\windows.x64.Debug\corerun.exe


Assert failure(PID 30596 [0x00007784], Thread: 37468 [0x925c]): saved_planned_regions_per_gen[0] >= to_be_empty_regions
    File: E:\git\runtime\src\coreclr\gc\gc.cpp Line: 31721
    Image: E:\git\runtime\artifacts\bin\coreclr\windows.x64.Debug\corerun.exe


Assert failure(PID 30596 [0x00007784], Thread: 35856 [0x8c10]): saved_planned_regions_per_gen[0] >= to_be_empty_regions
    File: E:\git\runtime\src\coreclr\gc\gc.cpp Line: 31721
    Image: E:\git\runtime\artifacts\bin\coreclr\windows.x64.Debug\corerun.exe


Assert failure(PID 30596 [0x00007784], Thread: 28252 [0x6e5c]): saved_planned_regions_per_gen[0] >= to_be_empty_regions
    File: E:\git\runtime\src\coreclr\gc\gc.cpp Line: 31721
    Image: E:\git\runtime\artifacts\bin\coreclr\windows.x64.Debug\corerun.exe


Assert failure(PID 30596 [0x00007784], Thread: 37336 [0x91d8]): saved_planned_regions_per_gen[0] >= to_be_empty_regions
    File: E:\git\runtime\src\coreclr\gc\gc.cpp Line: 31721
    Image: E:\git\runtime\artifacts\bin\coreclr\windows.x64.Debug\corerun.exe


Assert failure(PID 30596 [0x00007784], Thread: 33332 [0x8234]): saved_planned_regions_per_gen[0] >= to_be_empty_regions
    File: E:\git\runtime\src\coreclr\gc\gc.cpp Line: 31721
    Image: E:\git\runtime\artifacts\bin\coreclr\windows.x64.Debug\corerun.exe


Assert failure(PID 30596 [0x00007784], Thread: 44380 [0xad5c]): saved_planned_regions_per_gen[0] >= to_be_empty_regions
    File: E:\git\runtime\src\coreclr\gc\gc.cpp Line: 31721
    Image: E:\git\runtime\artifacts\bin\coreclr\windows.x64.Debug\corerun.exe

Note: the assertion doesn't happen every time, so it could be unrelated.

Reproduction Steps

Run the following code:

  public static long Allocate()
  {
      var array = new byte[100 * 1024 * 1024];

      long sum = 0;

      for (int i = 0; i < array.Length; i++)
      {
          sum += array[i];
      }

      return sum;
  }

static void Main()
{
    for (int i = 0; i < 10_000; i++)
    {
        Allocate();
    }
}

With:

DOTNET_GCHeapHardLimit=7D000000
DOTNET_gcServer=1

My machine has 12 cores and it seems to affect the problem, so you might have to adjust the number of heaps accordingly.

Expected behavior

The code runs without crashing.

Actual behavior

An OOM is thrown after 19 iterations.

Regression?

The problem seems related to regions. It happens in .NET 7 and 8, but I can't reproduce it in .NET 6 or when using clrgc.dll.

Known Workarounds

Use clrgc.dll or increase the heap limit.

Configuration

.NET 8 RC2
Windows x64

Other information

No response

Metadata

Metadata

Assignees

Labels

area-GC-coreclrin-prThere is an active PR which will close this issue when it is merged

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions