Make GC.GetGCMemoryInfo public (dotnet/corefx#37092)
authorLudovic Henry <luhenry@microsoft.com>
Tue, 23 Apr 2019 21:39:47 +0000 (14:39 -0700)
committerGitHub <noreply@github.com>
Tue, 23 Apr 2019 21:39:47 +0000 (14:39 -0700)
* Make GC.GetGCMemoryInfo public

Fix https://github.com/dotnet/corefx/issues/34631

* Fix uapaot framework

* Address review

* Add some tests

* Harden some tests

* Merge the GCMemoryInfo tests

* Simplify test

We are in a remote process, no need to clean up the GCHandle at the end of the test

Commit migrated from https://github.com/dotnet/corefx/commit/9e2f3b630a51875fc0455a7cabb8803f6527f81e

src/libraries/System.Runtime/ref/System.Runtime.cs
src/libraries/System.Runtime/src/ApiCompatBaseline.uapaot.txt
src/libraries/System.Runtime/tests/System/GCTests.netcoreapp.cs

index 8b4b2e4d09d908c14571c781b07b3629faa281c2..2646e062652b5fcac682877d9eecfa0df4543f3d 100644 (file)
@@ -1270,6 +1270,7 @@ namespace System
         public static int CollectionCount(int generation) { throw null; }
         public static void EndNoGCRegion() { }
         public static long GetAllocatedBytesForCurrentThread() { throw null; }
+        public static GCMemoryInfo GetGCMemoryInfo() { throw null; }
         public static int GetGeneration(object obj) { throw null; }
         public static int GetGeneration(System.WeakReference wo) { throw null; }
         public static long GetTotalMemory(bool forceFullCollection) { throw null; }
@@ -1288,6 +1289,14 @@ namespace System
         public static System.GCNotificationStatus WaitForFullGCComplete(int millisecondsTimeout) { throw null; }
         public static void WaitForPendingFinalizers() { }
     }
+    public readonly struct GCMemoryInfo
+    {
+        public long HighMemoryLoadThresholdBytes { get { throw null; } }
+        public long MemoryLoadBytes { get { throw null; } }
+        public long TotalAvailableMemoryBytes { get { throw null; } }
+        public long HeapSizeBytes { get { throw null; } }
+        public long FragmentedBytes { get { throw null; } }
+    }
     public enum GCCollectionMode
     {
         Default = 0,
index 7e2b2e12663773e3835dee110fbd58d989dc0d8d..5abd07bf1734c15cac3834f5d226871494d295d9 100644 (file)
@@ -16,3 +16,5 @@ MembersMustExist : Member 'System.Range.GetOffsetAndLength(System.Int32)' does n
 TypesMustExist : Type 'System.Range.OffsetAndLength' does not exist in the implementation but it does exist in the contract.
 CannotRemoveBaseTypeOrInterface : Type 'System.Memory<T>' does not implement interface 'System.IEquatable<System.Memory<T>>' in the implementation but it does in the contract.
 CannotRemoveBaseTypeOrInterface : Type 'System.ReadOnlyMemory<T>' does not implement interface 'System.IEquatable<System.ReadOnlyMemory<T>>' in the implementation but it does in the contract.
+MembersMustExist : Member 'System.GC.GetGCMemoryInfo()' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'System.GCMemoryInfo' does not exist in the implementation but it does exist in the contract.
index 4333cd67dda7c9f27f3e0be720c0ee7078019321..d01349369e40e001910da44c1935e7b4213dce35 100644 (file)
@@ -3,6 +3,8 @@
 // See the LICENSE file in the project root for more information.
 
 using System;
+using System.Runtime.InteropServices;
+using Microsoft.DotNet.RemoteExecutor;
 using Xunit;
 
 namespace System.Tests
@@ -23,5 +25,44 @@ namespace System.Tests
             Assert.True((end - start) > size, $"Allocated too little: start: {start} end: {end} size: {size}");
             Assert.True((end - start) < 5 * size, $"Allocated too much: start: {start} end: {end} size: {size}");
         }
+
+        [Fact]
+        public static void GetGCMemoryInfo()
+        {
+            RemoteExecutor.Invoke(() =>
+            {
+                // Allows to update the value returned by GC.GetGCMemoryInfo
+                GC.Collect();
+
+                GCMemoryInfo memoryInfo1 = GC.GetGCMemoryInfo();
+
+                Assert.True(memoryInfo1.HighMemoryLoadThresholdBytes > 0);
+                Assert.True(memoryInfo1.MemoryLoadBytes > 0);
+                Assert.True(memoryInfo1.TotalAvailableMemoryBytes > 0);
+                Assert.True(memoryInfo1.HeapSizeBytes > 0);
+                Assert.True(memoryInfo1.FragmentedBytes >= 0);
+
+                GCHandle[] gch = new GCHandle[64 * 1024];
+                for (int i = 0; i < gch.Length * 2; ++i)
+                {
+                    byte[] arr = new byte[64];
+                    if (i % 2 == 0)
+                    {
+                        gch[i / 2] = GCHandle.Alloc(arr, GCHandleType.Pinned);
+                    }
+                }
+
+                // Allows to update the value returned by GC.GetGCMemoryInfo
+                GC.Collect();
+
+                GCMemoryInfo memoryInfo2 = GC.GetGCMemoryInfo();
+
+                Assert.True(memoryInfo2.HighMemoryLoadThresholdBytes == memoryInfo1.HighMemoryLoadThresholdBytes);
+                Assert.True(memoryInfo2.MemoryLoadBytes >= memoryInfo1.MemoryLoadBytes);
+                Assert.True(memoryInfo2.TotalAvailableMemoryBytes == memoryInfo1.TotalAvailableMemoryBytes);
+                Assert.True(memoryInfo2.HeapSizeBytes > memoryInfo1.HeapSizeBytes);
+                Assert.True(memoryInfo2.FragmentedBytes > memoryInfo1.FragmentedBytes);
+            }).Dispose();
+        }
     }
 }