-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
This analysis was originally ran in parallel with the creation of DATAS (although we didn't know it at the time); we had thought that DATAS would just solve the problem after .NET 8 was released; however this has proven to not be the case due to #105780. We had been told to expect a fix in the first servicing release of .NET 9 ; however the fix was rolled back due to a bad interaction with WinForms.
Thus; it's time to weigh options; which is easier to do, track down and fix whatever is causing the bad interaction between DATAS, BGC and WinForms, or add more statistics methods.
The problem is, due to ebb and flow of usage of various processes on the server, the result is some processes hog all the system RAM and don't release it while other processes are scrambling to get enough. This can in the worst case cause the server to page, which thrashes RAM pretty badly when the GC finally does wake up on a big-allocation process.
The obvious solution is to run the GC based on something like heap growth; even a pretty naïve algorithm would work here better than what we are observing. In order to do this we would write a thread that looks something like this:
void GCDrive() {
var memory_current;
var memory_previous;
for(;;) {
memory_previous = memory_current;
memory_current = GC.???;
if (condition) {
GC.Collect();
GC.WaitForPendingFinalizers();
memory_previous = memory_current;
memory_current = GC.???;
}
System.Threading.Thread.Sleep(3000);
}
}
The problem comes in in filling the GC.??? argument; essentially I need a GC.GetTotalAllocatedBytesImmediate() method.
So what does this do that GC.GetTotalAllocatedBytes(Boolean) doesn't; it returns the true value without waiting for GC; since we don't need synchronous readout (that is; there is no need to lock out allocators while adding up the per-thread fresh heap pieces) this is actually possible. This would return all the allocated bytes not in the fresh heap (which will not have changed since the last GC run) and the distance between the bottom and the top of the fresh heap.
Other numbers I would need to know: the immediate size of the non-fresh heap, the immediate size of the fresh heap, and the immediate size of the memory pressure (see AddMemoryPressure() and RemoveMemoryPressure() for why I would want to do this).
I would definitely have to tune condition a few times to get it right; but even a banal version still behave quite reasonably if background GC is on; at least in comparison to what we are seeing that forced us the change the big servers to workstation GC.