Skip to content

[API Proposal]: GC.RefreshMemoryLimit #70601

@cshung

Description

@cshung

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

namespace System;
public static class GC
{
        /// <summary>
        ///
        /// Instructs the Garbage Collector to reconfigure itself by detecting the various memory limits on the system.
        ///
        /// In addition to actual physical memory limit and container limit settings, these configuration settings can be overwritten:
        ///
        /// - GCHeapHardLimit
        /// - GCHeapHardLimitPercent
        /// - GCHeapHardLimitSOH
        /// - GCHeapHardLimitLOH
        /// - GCHeapHardLimitPOH
        /// - GCHeapHardLimitSOHPercent
        /// - GCHeapHardLimitLOHPercent
        /// - GCHeapHardLimitPOHPercent
        ///
        /// Instead of updating the environment variable (which will not be read), these are overridden setting a ulong value in the AppContext.
        ///
        /// For example, you can use AppContext.SetData("GCHeapHardLimit", (ulong) 100 * 1024 * 1024) to override the GCHeapHardLimit to a 100M.
        ///
        /// As a limitation, for 32-bit systems (e.g. x86, ARM) or OSX, if we do not already have a heap hard limit set, we will not establish a new heap hard limit.
        ///
        /// As of now, this API is feature preview only and subject to changes as necessary.
        ///
        /// </summary>
        ///
        /// <returns> A status code to indicate the operation's result:
        /// 0 - The refresh operation succeed
        /// 1 - The operation failed because the new memory limit is too low
        /// 2 - The new hard limit configuration settings is invalid
        ///
        /// We reserve the rights to add more status code as we evolve the implementation.
        ///
        /// </returns>
        [System.Runtime.Versioning.RequiresPreviewFeaturesAttribute("RefreshMemoryLimit is in preview.")]
        public static int RefreshMemoryLimit()
}

API Usage

GC.RefreshMemoryLimit();

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

  1. Non-trivial work with various containers that we support, and
  2. No way to communicate if the container size reduction is infeasible (*).

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    api-approvedAPI was approved in API review, it can be implementedapi-suggestionEarly API idea and discussion, it is NOT ready for implementationarea-GC-coreclr

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions