Skip to content
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

Add an API to reduce GC memory usage #50902

Open
PeterSolMS opened this issue Apr 8, 2021 · 16 comments
Open

Add an API to reduce GC memory usage #50902

PeterSolMS opened this issue Apr 8, 2021 · 16 comments
Labels
api-approved API was approved in API review, it can be implemented area-GC-coreclr
Milestone

Comments

@PeterSolMS
Copy link
Contributor

Background and Motivation

In some cases, it's desirable for GC to reduce memory usage at the possible expense of increased GC pause times.

The best tradeoff between memory usage and GC pause time will depend on the scenario, so what is proposed below is a dial where a value of 0 specifies the default behavior, and higher values specify increasingly aggressive measures to keep GC heap size low.

Proposed API

    public static partial class GCOptimizationGoal
    {
        /// <summary>
        /// This property is a dial that tells GC to try to reduce memory usage.
        /// A value of 0 specifies the default behavior.
        /// Values 1 through 9 specify increasingly aggressive behavior to reduce
        /// memory usage, at the possible expense of increased GC pause time.
        /// </summary>
        public static int Memory { get; set; }
    }

Usage Examples

// Example 1:
// Keep heap size fairly low
GCOptimizationGoal.Memory = 7;

// Example 2:
// save setting
int savedMemorySetting = GCOptimizationGoal.Memory;
try
{
    // Relax memory goal for the following to reduce pause times
    GCOptimizationGoal.Memory = 0;
    // do work
}
finally
{
    // restore setting
    GCOptimizationGoal.Memory = savedMemorySetting;
}

-->

Alternative Designs

A plausible alternative would be to add a static property to the GCSettings class instead, for example:

    public static partial class GCSettings
    {
        // ... existing members ...

        /// <summary>
        /// This property is a dial that tells GC to try to reduce memory usage.
        /// A value of 0 specifies the default behavior.
        /// Values 1 through 9 specify increasingly aggressive behavior to reduce
        /// memory usage, at the possible expense of increased GC pause time.
        /// </summary>
        public static int OptimizeMemory { get; set; }
    }

Risks

The risks can be kept fairly low by making sure the default behavior stays the same. As mentioned above, at the higher settings GC pause times will increase.

@PeterSolMS PeterSolMS added the api-suggestion Early API idea and discussion, it is NOT ready for implementation label Apr 8, 2021
@dotnet-issue-labeler dotnet-issue-labeler bot added area-GC-coreclr untriaged New issue has not been triaged by the area owner labels Apr 8, 2021
@ghost
Copy link

ghost commented Apr 8, 2021

Tagging subscribers to this area: @dotnet/gc
See info in area-owners.md if you want to be subscribed.

Issue Details

Background and Motivation

In some cases, it's desirable for GC to reduce memory usage at the possible expense of increased GC pause times.

The best tradeoff between memory usage and GC pause time will depend on the scenario, so what is proposed below is a dial where a value of 0 specifies the default behavior, and higher values specify increasingly aggressive measures to keep GC heap size low.

Proposed API

    public static partial class GCOptimizationGoal
    {
        /// <summary>
        /// This property is a dial that tells GC to try to reduce memory usage.
        /// A value of 0 specifies the default behavior.
        /// Values 1 through 9 specify increasingly aggressive behavior to reduce
        /// memory usage, at the possible expense of increased GC pause time.
        /// </summary>
        public static int Memory { get; set; }
    }

Usage Examples

// Example 1:
// Keep heap size fairly low
GCOptimizationGoal.Memory = 7;

// Example 2:
// save setting
int savedMemorySetting = GCOptimizationGoal.Memory;
try
{
    // Relax memory goal for the following to reduce pause times
    GCOptimizationGoal.Memory = 0;
    // do work
}
finally
{
    // restore setting
    GCOptimizationGoal.Memory = savedMemorySetting;
}

-->

Alternative Designs

A plausible alternative would be to add a static property to the GCSettings class instead, for example:

    public static partial class GCSettings
    {
        // ... existing members ...

        /// <summary>
        /// This property is a dial that tells GC to try to reduce memory usage.
        /// A value of 0 specifies the default behavior.
        /// Values 1 through 9 specify increasingly aggressive behavior to reduce
        /// memory usage, at the possible expense of increased GC pause time.
        /// </summary>
        public static int OptimizeMemory { get; set; }
    }

Risks

The risks can be kept fairly low by making sure the default behavior stays the same. As mentioned above, at the higher settings GC pause times will increase.

Author: PeterSolMS
Assignees: -
Labels:

api-suggestion, area-GC-coreclr, untriaged

Milestone: -

@YairHalberstadt
Copy link
Contributor

GCOptimizationGoal.Memory isn't a very a clear name - I would in fact assume that higher amounts meant use more memory.

I think an enum would be clearer.

What if you want to go the opposite way? Use as much memory as you want to increase performance? I presume the server GC is tuned for that anyways so there's no need.

I think with 10 levels it's very difficult to decide which one to pick. Maybe 2 modes are all that's really necessary? Optimize space vs Optimize performance?

@Maoni0
Copy link
Member

Maoni0 commented Apr 8, 2021

GCOptimizationGoal.Memory isn't a very a clear name - I would in fact assume that higher amounts meant use more memory.
Optimize space vs Optimize performance?

that's interesting, when we talk about memory performance, it generally has 3 aspects, space (or more commonly referred to as memory size) is one of them. the other 2 are throughput/time and pause duration. this is explained here.

when folks talk about optimizing for an aspect, the convention from most folks I've worked with seems to be -

memory -> lower is better
time -> lower is better (which means throughput -> higher is better)
pause -> shorter is better

so when someone talks about "I want to optimize for memory" they mean "I want to use less memory".

interested to hear what other people think of this.

@mangod9
Copy link
Member

mangod9 commented Apr 12, 2021

@richlander since this is related to dotnet/core#5488. Perhaps we can broaden the knobs.

@mangod9 mangod9 removed the untriaged New issue has not been triaged by the area owner label Apr 12, 2021
@mangod9 mangod9 added this to the Future milestone Apr 12, 2021
@PeterSolMS
Copy link
Contributor Author

I think that having a dial is preferable over an enum because it allows for more fine-grained adjustment. Of course, some experimentation and measurement will be required to arrive at a suitable setting for each scenario, but a setting in the middle of the range (say 4 to 6) will be a reasonable starting point in most cases.

I am open to imroving the naming to reduce potential misunderstanding.

@Maoni0 Maoni0 added the api-ready-for-review API is ready for review, it is NOT ready for implementation label Apr 13, 2021
@Maoni0
Copy link
Member

Maoni0 commented Apr 13, 2021

since there haven't been many comments I think we can take this to API review folks to figure out the naming/convention/etc so I've set it to ready for review.

@Maoni0 Maoni0 added the blocking Marks issues that we want to fast track in order to unblock other important work label Apr 13, 2021
@richlander
Copy link
Member

This is interesting. The problem with these sorts of APIs is ensuring that it fits within an actual functioning app. For example, what's the data that would inform an app that it should ++ the value? If that data rich enough? We should get feedback from teams who run big sites (1P and 3P). I'm happy to help get that feedback.

@BreyerW
Copy link

BreyerW commented Apr 14, 2021

Would it be possible to actually reduce gc pauses at the expense of bigger memory consumption compared to current default? I mean lets say increase allowed level to 11-15 and default level would be 2-5 and that would mean current behaviour while values lower than default would make gc "lazier" than now. Or there wont be any meangiful gains because gc is already as "lazy" as possible?

@jkotas
Copy link
Member

jkotas commented Apr 15, 2021

A plausible alternative would be to add a static property to the GCSettings class instead

This looks better to me as it is similar to the existing GCSettings.LatencyMode property. We try to avoid having types that have just a single or very few members.

@bartonjs
Copy link
Member

bartonjs commented Apr 15, 2021

Video

  • We changed the int 0-9 to a double 0-1
  • We moved it onto GCSettings and renamed it.
  • Otherwise, looks good.
namespace System.Runtime
{
    partial static class GCSettings
    {
        // NaN represents "there is no goal"
        // Setter throws for things outside the range [0, 1] union NaN
        public static double MemoryOptimizationGoal { get; set; }
    }
}

@bartonjs bartonjs added api-approved API was approved in API review, it can be implemented and removed api-ready-for-review API is ready for review, it is NOT ready for implementation labels Apr 15, 2021
@stephentoub stephentoub removed the blocking Marks issues that we want to fast track in order to unblock other important work label Apr 15, 2021
@davidfowl
Copy link
Member

Doesn't seem like this is implemented yet. @PeterSolMS is this still on track of .NET 6?

@terrajobst terrajobst removed the api-suggestion Early API idea and discussion, it is NOT ready for implementation label Jun 25, 2021
@madhub
Copy link

madhub commented Feb 16, 2022

Any update ?, is it planned for .NET 7
How does it related to Workstation or Server GC setting ? Does it automatically select GC mode based on this setting ?

@huoyaoyuan
Copy link
Member

@madhub It needs real implementation in GC. We don't want to expose such API in advance with no actual effect.

How does it related to Workstation or Server GC setting ? Does it automatically select GC mode based on this setting ?

I don't think they should be related. There are more behavior difference between workstation and server GC.

@deeprobin
Copy link
Contributor

Video

* We changed the int 0-9 to a double 0-1

* We moved it onto GCSettings and renamed it.

* Otherwise, looks good.
namespace System.Runtime
{
    partial static class GCSettings
    {
        // NaN represents "there is no goal"
        // Setter throws for things outside the range [0, 1] union NaN
        public static double MemoryOptimizationGoal { get; set; }
    }
}

@bartonjs

Wouldn't a float suffice for this case?

@bartonjs
Copy link
Member

Wouldn't a float suffice for this case?

Possibly; but double is the go-to type in .NET for floating point values (just like how we use int even for API only capable of expressing values like 0..10)). System.Single only makes it into API when there's a compelling reason.

I doubt that the GC's backing integer values will ever exceed 24 bits of granularity, so System.Single probably isn't limiting; but it's a bit unnatural, and this API shouldn't really be on any hot path that would warrant the squeeze.

@deeprobin
Copy link
Contributor

Can any of you explain roughly what this change involves on the GC side?

If this is a simple topic for beginners, it would certainly be interesting for me, because I have not had much to do with the GC.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api-approved API was approved in API review, it can be implemented area-GC-coreclr
Projects
None yet
Development

No branches or pull requests