dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
15.39k stars 4.75k forks source link

[API Proposal]: Add TotalPhysicalMemory and TotalVirtualMemory properties to the Environment class #79146

Open andrasfuchs opened 1 year ago

andrasfuchs commented 1 year ago

Background and motivation

The System.Environment class has many useful properties regarding the environment where the process runs, but it doesn't currently have properties about the total and free amount of physical and virtual memories. These are very important metrics, especially for computation-intensive projects like ML.NET's machine learning.

It would be great if the Environment class would have more properties describing the total and free amounts of physical and virtual memories.

API Proposal

namespace System
{
    public static partial class Environment
    {
        public static long? TotalPhysicalMemory { get; }
        public static long? FreePhysicalMemory { get; }
        public static long? TotalVirtualMemory { get; }
        public static long? FreeVirtualMemory  { get; }
    }
}

API Usage

    // Get the total physical memory (in bytes)
    var totalRam = Environment.TotalPhysicalMemory;

    // Get the total physical memory (in bytes)
    var freeRam = Environment.FreePhysicalMemory ;

    // Get the total physical memory (in bytes)
    var totalVM = Environment.TotalVirtualMemory;

    // Get the total physical memory (in bytes)
    var freeVM = Environment.FreeVirtualMemory;

Alternative Designs

if (OperatingSystem.IsWindows())
{
    ObjectQuery wql = new ObjectQuery("SELECT * FROM Win32_OperatingSystem");
    ManagementObjectSearcher searcher = new ManagementObjectSearcher(wql);
    ManagementObjectCollection results = searcher.Get();

    foreach (ManagementObject result in results)
    {
        ulong totalVisibleMemorySize = (ulong)result["TotalVisibleMemorySize"];
        ulong freePhysicalMemory = (ulong)result["FreePhysicalMemory"];
        ulong totalVirtualMemorySize = (ulong)result["TotalVirtualMemorySize"];
        ulong freeVirtualMemory = (ulong)result["FreeVirtualMemory"];
    }
}

Risks

It's not a risk per say, but these new properties would require some extra work, because we would need to call platform-specific APIs. Virtual memory is used on Windows, Linux, Android and iOS, so the appropriate APIs should be available on those, but I'm not sure about others that .NET supports.

I would define these new properties as nullable types, because I can image that some .NET supported operating system doesn't support these reports regarding memory usage. Also, if it's not implemented on a specific platform, they could return null.

dotnet-issue-labeler[bot] commented 1 year ago

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

andrasfuchs commented 1 year ago

I can't change labels on this issue, but I think the best area label would be area-System.Diagnostics.Process. @jeffhandley

ghost commented 1 year ago

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

Issue Details
### Background and motivation The [System.Environment class](https://github.com/dotnet/runtime/blob/main/src/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.cs) has many useful properties regarding the environment where the process runs, but it doesn't currently have properties about the total and free amount of physical and virtual memories. These are very important metrics, especially for computation-intensive projects like [ML.NET's machine learning](https://github.com/dotnet/machinelearning). It would be great if the Environment class would have more properties describing the total and free amounts of physical and virtual memories. ### API Proposal ```csharp namespace System { public static partial class Environment { public static long? TotalPhysicalMemory { get; } public static long? FreePhysicalMemory { get; } public static long? TotalVirtualMemory { get; } public static long? FreeVirtualMemory { get; } } } ``` ### API Usage ```csharp // Get the total physical memory (in bytes) var totalRam = Environment.TotalPhysicalMemory; // Get the total physical memory (in bytes) var freeRam = Environment.FreePhysicalMemory ; // Get the total physical memory (in bytes) var totalVM = Environment.TotalVirtualMemory; // Get the total physical memory (in bytes) var freeVM = Environment.FreeVirtualMemory; ``` ### Alternative Designs ```csharp if (OperatingSystem.IsWindows()) { ObjectQuery wql = new ObjectQuery("SELECT * FROM Win32_OperatingSystem"); ManagementObjectSearcher searcher = new ManagementObjectSearcher(wql); ManagementObjectCollection results = searcher.Get(); foreach (ManagementObject result in results) { ulong totalVisibleMemorySize = (ulong)result["TotalVisibleMemorySize"]; ulong freePhysicalMemory = (ulong)result["FreePhysicalMemory"]; ulong totalVirtualMemorySize = (ulong)result["TotalVirtualMemorySize"]; ulong freeVirtualMemory = (ulong)result["FreeVirtualMemory"]; } } ``` ### Risks It's not a risk per say, but these new properties would require some extra work, because we would need to call platform-specific APIs. Virtual memory is used on Windows, Linux, Android and iOS, so the appropriate APIs should be available on those, but I'm not sure about others that .NET supports. I would define these new properties as nullable types, because I can image that some .NET supported operating system doesn't support these reports regarding memory usage. Also, if it's not implemented on a specific platform, they could return null.
Author: andrasfuchs
Assignees: -
Labels: `api-suggestion`, `area-System.Runtime`, `untriaged`
Milestone: -
dakersnar commented 1 year ago

Unfortunately, if you are referring to managed memory, the GC is going to make this set of APIs unfeasible. The GC will often only collect when allocations are requested, so at any given moment, the amount of memory that is technically free (which is what your API would return) could be way smaller than the amount of memory that would be free after a GC run. The only way to produce an accurate answer would be to kick off a GC run before checking how much free memory there is, but that would be both expensive and inconsistent. Closing for this reason, but feel free to request a reopen if I'm missing something.

andrasfuchs commented 1 year ago

I partially agree with your reasoning, but I still think that having an API to get the free memory would be useful.

In our use case for example, ML.NET often runs unmanaged code for the machine learning training process and knowing the available free memory during that training would be crucial, because we need to prevent a system-wide crash that normally happens if we don't cancel the training on time before we run out of virtual memory.

I agree that calling GC before every free memory call would be wasteful and impractical.

tannergooding commented 1 year ago

Checks against the "virtual memory space" aren't typically meaningful. On a 64-bit system, you'll have at least 48-bits of addressable virtual address space. The more meaningful information is the available physical memory.

If such an API were provided, it would likely be part of System.Runtime.InteropServices.NativeMemory as that is where the Alloc/Free APIs are exposed.

That being said, there are often better ways to manage such memory than simply checking how much physical memory is available and there can often be other considerations required as part of that. If you know you're working with large data and can do streaming, it is often more beneficial to have your algorithms use that to minify the amount of total overhead required.

andrasfuchs commented 1 year ago

As far as I know the virtual memory space is also constrained by the space available on the swap partition(s) and/or the maximum swap file size settings, so the total and free virtual memory is a useful metric, especially in the use cases like ours with ML.NET, because if we don't monitor it closely it can cause a system-wide crash.

From he user's perspective it would make more sense to have these values available on the System.Environment class, that's where we would look for it, even if the actual memory allocations are happening elsewhere.

ericstj commented 5 months ago

This came up again recently where folks are using System.Management for this as we have no lower level API. System.Management is very heavy and not currently AOT friendly nor cross-plat. It would be good if we could expose some API here for diagnostics purposes.