-
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
[API Proposal]: GC.RefreshMemoryLimit #70601
Comments
Tagging subscribers to this area: @dotnet/gc Issue DetailsBackground and motivationIn a cloud service scenario, demand comes and goes. To be cost-effective, it is important that our services can scale up and scale down on resource consumption as the demand fluctuates. While the GC is capable of de-commit unused memory (using aggressive GC manually or waiting until the automatic aging de-commit kicks in), there is no guarantee that the application is not going to allocate more as requests come back. It is much safer if we allow the container to shrink its memory limit after the scale down happened so that the operator can put more instances on the box without worrying about running out of memory just because the GC heuristics believe they are more memory than it is. As of now, we can change the container limit as we wish, but the GC won't notice. Here I propose an API to notify the GC when that happens. API Proposalnamespace System;
public static class GC
{
// ...
bool RefreshMemoryLimit();
} API UsageGC.RefreshMemoryLimit(); Alternative DesignsAn alternative design is to have some system mechanism that do that automatically when the container memory limit change happens. This will involve
Risks(*) We reserve the right to refuse the container size reduction when it is infeasible (it might be too tight, leaving the GC no room to maneuver). But the operator might have already reduced the container size - hmm - we need to do something about that. Certain things can't easily change - it is easy to say that we wanted to reduce the number of cores as well, but it would be hard to implement changing the number of heaps. Here is a proof-of-concept prototype, feel free to try it out and leave us feedback.
|
Reloading memory is awesome. I support the manual API instead of auto refreshing. |
Related: |
This API would be important for us at AWS. For .NET AWS Lambda functions the .NET runtime does not understand the memory limits put in place by the Lambda runtime. If we had this method available to us we could as part of our .NET Lambda startup code take the value from the AWS_LAMBDA_FUNCTION_MEMORY_SIZE environment variable set by the Lambda service into a value for |
@normj, as I tried to implement the logic to read the After discussing with @AaronRobinsonMSFT, we believe the better approach is to communicate these values through |
@cshung If I understand correctly I could detect what the actual memory limit is based on the Lambda runtime environment and then call something like the following
That seems cleaner then setting an in-process environment variable and then pinging the .NET runtime to go take another look at the environment variables. |
Out of curiosity assuming the memory value being set is still significantly greater then what is currently being consumed will there be any performance cost setting a new memory limit? |
In the short term - the act of setting the limit itself won't cost much, all it does is walk the heap data structures and set some integer fields. In the long term - obviously - how the application performs after switching the limits depends on what the application does. One way to think about the problem is to think of this API as switching gears. How fast the car runs depends on a lot of stuff, how much gas you give (i.e. allocations), whether are you running against a slope (i.e. survivals), and what gears you are on. Your car probably won't slow down right away when you tune down the gears, but hopefully, eventually, it will as the car moved longer and the pedals are off. I'd love to see that after refreshing the memory limit, after a reasonable amount of time to let the current situation change, the application should behave as if the memory limit was specified during startup. While that's an ideal situation I would like to see, the reality may or may not be what we wanted it to be. The best way to tell is to actually experiment with it. |
Thanks for the info @cshung. In AWS Lambda we are most sensitive to anything that affects startup which also includes bootstrapping the Lambda runtime. When we have this API we would make the call really early in our startup process so at that point there shouldn't be much memory usage. So I'm hoping us telling the .NET runtime the true memory limit early in the startup phase should have negligible affect to startup performance. |
@normj, @davidni, @zackliu: A private implementation of the API is now implemented and merged in the main branch as #83707, it will be available as part of .NET 8 Preview 4. This is currently implemented as a private API to allow trying out without committing to the API shape just yet. Please try it out and let me know if you hit any issues. |
@cshung My use cases for needing this API are on Linux so the current limitation for the PR being for windows only will make it hard to meaningfully try this out. |
The code should work for all platforms since the change is not platform specific. In fact, it compiles and passed all the existing tests we have for all platforms we support. The PR comment was inaccurate and I updated it. The comment really meant I haven't got a setup to test it on Linux/OSX yet. If you could help and see if that actually works on Linux for your scenario, that would be great. |
@cshung Great! I'll give it a try when preview 4 is released |
namespace System;
public static partial class GC
{
[System.Runtime.Versioning.RequiresPreviewFeaturesAttribute("RefreshMemoryLimit is in preview.")]
public static int RefreshMemoryLimit()
} |
This is not how we are designing hosting APIs these days. Anything people need for hosting, we design it as first-class managed API first and then tell people to wrap it in an interop wrapper for hosting If we add this API in the current shape, it is creating bad precent for introducing unnaturally looking APIs any time somebody wants to call something from unmanaged host. |
@jkotas So you think the enum approach is better, then? |
The return value indicates error conditions. The API should return |
That was the first thing I asked for in the API review meeting :) but was told we couldn't do that because common usage would be from native code via hosting APIs and exception throwing would be problematic for that. If that's not the case, please do make it void and throw for errors. |
We are still planning to call this API through the hosting API, but we are working towards a scheme that would allow the caller to catch the exception by having some sort of injected managed wrapper functions. Once we have got this sorted out we can move towards using exceptions instead of error codes. |
I'm trying to test this out as part of Preview 4 but I'm not seeing any changes. I suspect I'm calling the What I'm doing is at the start of my app I'm running this method using reflection to call the current private
But then later when I call |
Thanks for trying it out! I think you need |
@cshung No luck still. I used your My current version of adjusting memory
|
Sorry for the confusion, I think I missed a couple of things. When I ran locally, I am seeing a bad bug that crashes on the first GC. The problem is that I accidentally swapped an assignment statement. I am going to get it fixed as soon as I can. |
Using When we add support for .NET 8 in AWS Lambda I can add in our runtime startup code something like the following to look for the AWS Lambda memory size and configure the .NET runtime with the configured value unless the user had already configured a value less then that.
|
@cshung will validate this with another customer. |
@cshung assume this issue is ok to close now? |
If this matters I was planning implementing the above code for real in AWS Lambda based on latest previews this month to make sure everything is working as expected. |
Closing as done. |
Background and motivation
In a cloud service scenario, demand comes and goes. To be cost-effective, it is important that our services can scale up and scale down on resource consumption as the demand fluctuates.
While the GC is capable of de-commit unused memory (using aggressive GC manually or waiting until the automatic aging de-commit kicks in), there is no guarantee that the application is not going to allocate more as requests come back. It is much safer if we allow the container to shrink its memory limit after the scale down happened so that the operator can put more instances on the box without worrying about running out of memory just because the GC heuristics believe they are more memory than it is.
As of now, we can change the container limit as we wish, but the GC won't notice. Here I propose an API to notify the GC when that happens.
API Proposal
API Usage
Alternative Designs
An alternative design is to have some system mechanism that do that automatically when the container memory limit change happens. This will involve
The API is meant to be used by people who host services. Therefore it makes sense to make sure this API is CLR Hosting API friendly.
Risks
(*) We reserve the right to refuse the container size reduction when it is infeasible (it might be too tight, leaving the GC no room to maneuver).
But the operator might have already reduced the container size - hmm - we need to do something about that.
Certain things can't easily change - it is easy to say that we wanted to reduce the number of cores as well, but it would be hard to implement changing the number of heaps.
Here is a proof-of-concept prototype, feel free to try it out and leave us feedback.
The text was updated successfully, but these errors were encountered: