-
Notifications
You must be signed in to change notification settings - Fork 5.4k
Description
Description
We are running lots of instances of kestrel .net core processes on a server machines.
Using DOTNET_GCHeapHardLimitPercent we tried to limit the memory of a single process instance (to 128GB), so that it would be impossible for a single process to take all machine memory (256GB). This seems to work but has completely unexpected negative side effects on total memory consumption. Running the process requires about approx. 350-400MB of private memory and has a memory commit size as follows:
- Reference Windows; 8 core; 32GB; NOT using DOTNET_GCHeapHardLimit: 0.6GB
- Reference Windows; 8 core; 32GB; using DOTNET_GCHeapHardLimit: 2.0GB
- Server Windows; 16 core; 256GB; using DOTNET_GCHeapHardLimit: 6.5GB
- Server Windows; 28 core; 256GB; using DOTNET_GCHeapHardLimit: 10.5GB
We expect to run 100+ of those processes on one of the machines, but this is impossible with this commit sizes because the processes get an OutOfMemoryException (or other OOMs) instantly.
Worst case the commit size is 30 times larger than the private memory used!
Reproduction Steps
Please note that we are NOT running in containers.
Take a .net core process.
Set DOTNET_GCHeapHardLimitPercent to a high value (e.g. 75%) on a machine with lots of RAM (e.g. 256GB) many cores (e.g. 28) and observe an extremely high memory commit.
Expected behavior
Using DOTNET_GCHeapHardLimitPercent should not create extremely high memory commits compared to not using this switch. It should LIMIT memory, not enlarge it (and certainly not by unreasonable dimensions).
Actual behavior
If you set DOTNET_GCHeapHardLimit to large memory sizes it consumes high amounts of commit memory (much larger than when not setting DOTNET_GCHeapHardLimit at all) for no clear reason.
Please note that setting other switches seems to have no or little effect (see list below)
Here are some measurements with different settings on a machine with 8 cores, 32GB RAM:
[DEFAULT]
Physical: 380
Private: 340
Commit: 650
DOTNET_GCConserveMemory=9
Physical: 380
Private: 340
Commit: 650
DOTNET_GCHeapHardLimitPercent=A (10%)
Physical: 380
Private: 340
Commit: 620
DOTNET_GCHeapHardLimitPercent=5 (5%)
Physical: 350
Private: 310
Commit: 480
DOTNET_GCHeapHardLimitPercent=5A (90%)
Physical: 380
Private: 340
Commit: 2000
DOTNET_GCHeapHardLimitPercent=5A (90%)
DOTNET_GCHeapCount=4
Physical: 400
Private: 355
Commit: 2000
DOTNET_GCHeapHardLimitPercent=5A (90%)
DOTNET_GCHeapCount=1
Physical: 400
Private: 360
Commit: 2000
DOTNET_GCHeapHardLimitPercent=5A (90%)
DOTNET_GCHeapCount=1
DOTNET_GCHighMemPercent=5
Physical: 400
Private: 360
Commit: 2000
DOTNET_GCHeapHardLimitPercent=5A (90%)
DOTNET_GCHeapCount=1
DOTNET_GCConserveMemory=9
Physical: 300
Private: 350
Commit: 1900
DOTNET_GCHeapHardLimitPercent=5A (90%)
DOTNET_GCHeapCount=100
Physical: 380
Private: 340
Commit: 2000
Regression?
No response
Known Workarounds
None/not using DOTNET_GCHeapHardLimit at all
Configuration
.Net Core 6; Windows
Other information
No response