-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to tell how much memory a .NET 6 application is really using? #76249
Comments
Tagging subscribers to this area: @dotnet/gc Issue DetailsFollowing on from #52592 (which is locked now)... We tried upgrading our application from .NET Core 3.1 to .NET 6 again and, as @PeterSolMS wrote in #52592 (comment), memory is not released to the OS until the server is low on RAM. (This is #37894, right?) The problem this creates for us is that we do not know how much RAM a server really has available to run more applications! We previously used Resident Set Size for this (on Ubuntu 18.04). The managed memory size reported by How can we tell how much RAM is actually needed by a .NET 6 application and how much would be available to other applications if they tried to use it?
|
From the GC's perspective, The GC doesn't know how much memory is used by SQLite either, so it cannot report how much memory is needed to run the application. But it knows two things.
Suppose:
Then you could compute the currently in use memory by: currently in use = resident set - total committed bytes + get total memory. Also, note that the memory currently in use is not the same thing as "how much memory is needed?". These days, many libraries adjust their memory usage based on available memory (and thus trade off other performance characteristics, such as latency or throughput), so you might be trying to hit a moving target. Once the memory is committed for one application, the OS cannot use that memory for another application, even when it is considered unused by the application. GC has no way to know that another application wanted to use it and therefore relinquish memory for other applications' use, we need someone to tell us that, and here is how:
|
Thanks for such a prompt and detailed response @cshung!
I will try out your formula as soon as I can, but just to make sure I understand it correctly: this is equivalent to I'd have to add the swapped out RAM (VmSwap from /proc/*/status) to RSS as well, I suppose. |
Yes, that's the idea behind that formula. Although I would say
|
Also, just to confirm, it seems that
right? |
Hmm, it seems that on Windows
|
@Maoni0 There could be some merit in having GC return this kind of "held back" OS memory based on time. If I imagine a busy server running a bunch of .NET processes (incl. 3rd party applications, tools, tray icon applications, services, ...), the amount of "optional" commit could sum up. Maybe the GC could make a push to release stuff based on time, for example, after a minute of relative idleness. This is relevant for desktop machines as well. Process Explorer shows quite a few .NET processes (colored in yellow) on my desktop (which is currently running 300 processes). Applications can do this cleanup themselves but most will not. If .NET included something sensible out of the box, that would help most machines converge to lower long-term memory usage. Defaults matter, and I have always appreciated the relatively low need to tune the .NET GC and to know its internals. |
This new strategy of .NET hogging RAM until it needs to be released is still causing problems for us. Here is the RAM usage of an application that was moved from server A to server B to server C: On the left "managed" is from Server A (Ubuntu 18.04) has 1024 GB RAM, 316 GB free. We're seeing this effect with many instances of the application (with different traffic) when moved to server B, not just one. This makes it very difficult to utilize it efficiently, as we don't know how much more RAM it really has available before applications start slowing down. Historically, on .NET 3.1 and earlier, this happened at RSS around 70-80% of physical RAM. It's unclear where the threshold is for .NET 6. Edit: Apparently this is not a new issue in .NET 6, but something about that server. The same happened with an old version of our application running on .NET 3.1.32 when moved between those same 3 servers: |
Following on from #52592 (which is locked now)... We tried upgrading our application from .NET Core 3.1 to .NET 6 again and, as @PeterSolMS wrote in #52592 (comment), memory is not released to the OS until the server is low on RAM. (This is #37894, right?)
The problem this creates for us is that we do not know how much RAM a server really has available to run more applications! We previously used Resident Set Size for this (on Ubuntu 18.04). The managed memory size reported by
GC.GetTotalMemory()
gives us some idea, but it's not enough - there is always a significant amount of unmanaged memory use, too, and that may increase and become more uncertain if we start using something like SQLite, for example.How can we tell how much RAM is actually needed by a .NET 6 application and how much would be available to other applications if they tried to use it?
The text was updated successfully, but these errors were encountered: