From 7d8f5dab8219da3d6fca575236ddd5e9e12f02f2 Mon Sep 17 00:00:00 2001 From: Andrew Au Date: Tue, 17 May 2022 12:18:13 -0700 Subject: [PATCH 1/6] Aggressive GC --- .../src/System/GC.CoreCLR.cs | 13 ++++- src/coreclr/gc/gc.cpp | 56 ++++++++++++++++++- src/coreclr/gc/gc.h | 1 + src/coreclr/gc/gcinterface.h | 3 +- .../src/System/GC.NativeAot.cs | 13 ++++- .../System.Runtime/ref/System.Runtime.cs | 1 + .../src/System/GC.Mono.cs | 5 +- src/tests/GC/API/GC/Collect_Aggressive.cs | 36 ++++++++++++ src/tests/GC/API/GC/Collect_Aggressive.csproj | 13 +++++ 9 files changed, 132 insertions(+), 9 deletions(-) create mode 100644 src/tests/GC/API/GC/Collect_Aggressive.cs create mode 100644 src/tests/GC/API/GC/Collect_Aggressive.csproj diff --git a/src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs index d6474dcc8c83d3..2c7716a501723d 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs @@ -23,7 +23,8 @@ public enum GCCollectionMode { Default = 0, Forced = 1, - Optimized = 2 + Optimized = 2, + Aggressive = 3, } // !!!!!!!!!!!!!!!!!!!!!!! @@ -35,6 +36,7 @@ internal enum InternalGCCollectionMode Blocking = 0x00000002, Optimized = 0x00000004, Compacting = 0x00000008, + Aggressive = 0x00000010, } // !!!!!!!!!!!!!!!!!!!!!!! @@ -197,7 +199,7 @@ public static void Collect(int generation, GCCollectionMode mode, bool blocking, throw new ArgumentOutOfRangeException(nameof(generation), SR.ArgumentOutOfRange_GenericPositive); } - if ((mode < GCCollectionMode.Default) || (mode > GCCollectionMode.Optimized)) + if ((mode < GCCollectionMode.Default) || (mode > GCCollectionMode.Aggressive)) { throw new ArgumentOutOfRangeException(nameof(mode), SR.ArgumentOutOfRange_Enum); } @@ -209,6 +211,13 @@ public static void Collect(int generation, GCCollectionMode mode, bool blocking, { iInternalModes |= (int)InternalGCCollectionMode.Optimized; } + else if (mode == GCCollectionMode.Aggressive) + { + iInternalModes |= (int)InternalGCCollectionMode.Aggressive; + // TODO, andrewau, someone intentionally set these flags to false should cause an exception? + blocking = true; + compacting = true; + } if (compacting) iInternalModes |= (int)InternalGCCollectionMode.Compacting; diff --git a/src/coreclr/gc/gc.cpp b/src/coreclr/gc/gc.cpp index e42d29365f7225..9e1fea7109aa33 100644 --- a/src/coreclr/gc/gc.cpp +++ b/src/coreclr/gc/gc.cpp @@ -211,6 +211,7 @@ BOOL is_induced (gc_reason reason) (reason == reason_lowmemory) || (reason == reason_lowmemory_blocking) || (reason == reason_induced_compacting) || + (reason == reason_induced_aggressive) || (reason == reason_lowmemory_host) || (reason == reason_lowmemory_host_blocking)); } @@ -221,6 +222,7 @@ BOOL is_induced_blocking (gc_reason reason) return ((reason == reason_induced) || (reason == reason_lowmemory_blocking) || (reason == reason_induced_compacting) || + (reason == reason_induced_aggressive) || (reason == reason_lowmemory_host_blocking)); } @@ -12297,6 +12299,48 @@ void gc_heap::distribute_free_regions() { #ifdef USE_REGIONS const int kind_count = large_free_region + 1; + if (settings.reason == reason_induced_aggressive) + { +#ifdef MULTIPLE_HEAPS + for (int i = 0; i < n_heaps; i++) + { + gc_heap* hp = g_heaps[i]; + int hn = i; +#else //MULTIPLE_HEAPS + { + gc_heap* hp = pGenGCHeap; + int hn = 0; +#endif //MULTIPLE_HEAPS + for (int kind = basic_free_region; kind < count_free_region_kinds; kind++) + { + global_regions_to_decommit[kind].transfer_regions (&hp->free_regions[kind]); + } + while (hp->decommit_step()) + { + } + for (int i = 0; i < total_generation_count; i++) + { + generation* generation = hp->generation_of(i); + heap_segment* region = generation_start_segment (generation); + region = heap_segment_rw (region); + while (region != nullptr) + { + uint8_t* aligned_allocated = align_on_page (heap_segment_allocated (region)); + size_t end_space = heap_segment_committed (region) - aligned_allocated; + if (end_space > 0) + { + virtual_decommit (aligned_allocated, end_space, gen_to_oh (i), hn); + heap_segment_committed (region) = aligned_allocated; + heap_segment_used (region) = min (heap_segment_used (region), heap_segment_committed (region)); + assert (heap_segment_committed (region) > heap_segment_mem (region)); + } + region = heap_segment_next_rw (region); + } + } + } + + return; + } // first step: accumulate the number of free regions and the budget over all heaps // and move huge regions to global free list @@ -30568,6 +30612,10 @@ void gc_heap::update_start_tail_regions (generation* gen, inline bool gc_heap::should_sweep_in_plan (heap_segment* region) { + if (settings.reason == reason_induced_aggressive) + { + return false; + } bool sip_p = false; int gen_num = get_region_gen_num (region); int new_gen_num = get_plan_gen_num (gen_num); @@ -40211,7 +40259,7 @@ BOOL gc_heap::decide_on_compacting (int condemned_gen_number, get_gc_data_per_heap()->set_mechanism (gc_heap_compact, compact_last_gc); } - if (settings.reason == reason_induced_compacting) + if (settings.reason == reason_induced_compacting || settings.reason == reason_induced_aggressive) { dprintf (2, ("induced compacting GC")); should_compact = TRUE; @@ -45233,7 +45281,11 @@ GCHeap::GarbageCollectTry (int generation, BOOL low_memory_p, int mode) if (reason == reason_induced) { - if (mode & collection_compacting) + if (mode & collection_aggressive) + { + reason = reason_induced_aggressive; + } + else if (mode & collection_compacting) { reason = reason_induced_compacting; } diff --git a/src/coreclr/gc/gc.h b/src/coreclr/gc/gc.h index a47f84089bc431..b3d771bd34fafd 100644 --- a/src/coreclr/gc/gc.h +++ b/src/coreclr/gc/gc.h @@ -74,6 +74,7 @@ enum gc_reason reason_bgc_tuning_soh = 14, reason_bgc_tuning_loh = 15, reason_bgc_stepping = 16, + reason_induced_aggressive = 17, reason_max }; diff --git a/src/coreclr/gc/gcinterface.h b/src/coreclr/gc/gcinterface.h index a1edb39e59fcb3..669be562ca05cb 100644 --- a/src/coreclr/gc/gcinterface.h +++ b/src/coreclr/gc/gcinterface.h @@ -275,7 +275,8 @@ enum collection_mode collection_non_blocking = 0x00000001, collection_blocking = 0x00000002, collection_optimized = 0x00000004, - collection_compacting = 0x00000008 + collection_compacting = 0x00000008, + collection_aggressive = 0x00000010 #ifdef STRESS_HEAP , collection_gcstress = 0x80000000 #endif // STRESS_HEAP diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/GC.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/GC.NativeAot.cs index b4d59af8f3655b..84d1ac939ca3f4 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/GC.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/GC.NativeAot.cs @@ -22,7 +22,8 @@ public enum GCCollectionMode { Default = 0, Forced = 1, - Optimized = 2 + Optimized = 2, + Aggressive = 3, } public enum GCNotificationStatus @@ -40,6 +41,7 @@ internal enum InternalGCCollectionMode Blocking = 0x00000002, Optimized = 0x00000004, Compacting = 0x00000008, + Aggressive = 0x00000010 } internal enum StartNoGCRegionStatus @@ -124,7 +126,7 @@ public static void Collect(int generation, GCCollectionMode mode, bool blocking, throw new ArgumentOutOfRangeException(nameof(generation), SR.ArgumentOutOfRange_GenericPositive); } - if ((mode < GCCollectionMode.Default) || (mode > GCCollectionMode.Optimized)) + if ((mode < GCCollectionMode.Default) || (mode > GCCollectionMode.Aggressive)) { throw new ArgumentOutOfRangeException(nameof(mode), SR.ArgumentOutOfRange_Enum); } @@ -135,6 +137,13 @@ public static void Collect(int generation, GCCollectionMode mode, bool blocking, { iInternalModes |= (int)InternalGCCollectionMode.Optimized; } + else if (mode == GCCollectionMode.Aggressive) + { + iInternalModes |= (int)InternalGCCollectionMode.Aggressive; + // TODO, andrewau, someone intentionally set these flags to false should cause an exception? + blocking = true; + compacting = true; + } if (compacting) { diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index bcfaa53f8fa3fa..af367a4bdda082 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -2567,6 +2567,7 @@ public enum GCCollectionMode Default = 0, Forced = 1, Optimized = 2, + Aggressive = 3, } public readonly partial struct GCGenerationInfo { diff --git a/src/mono/System.Private.CoreLib/src/System/GC.Mono.cs b/src/mono/System.Private.CoreLib/src/System/GC.Mono.cs index b5bc27542b5fef..681a8cc03bbaa4 100644 --- a/src/mono/System.Private.CoreLib/src/System/GC.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/GC.Mono.cs @@ -11,7 +11,8 @@ public enum GCCollectionMode { Default = 0, Forced = 1, - Optimized = 2 + Optimized = 2, + Aggressive = 3, } public enum GCNotificationStatus @@ -91,7 +92,7 @@ public static void Collect(int generation, GCCollectionMode mode, bool blocking, { if (generation < 0) throw new ArgumentOutOfRangeException(nameof(generation), "generation", SR.ArgumentOutOfRange_GenericPositive); - if ((mode < GCCollectionMode.Default) || (mode > GCCollectionMode.Optimized)) + if ((mode < GCCollectionMode.Default) || (mode > GCCollectionMode.Aggressive)) throw new ArgumentOutOfRangeException(nameof(mode), SR.ArgumentOutOfRange_Enum); InternalCollect(generation); diff --git a/src/tests/GC/API/GC/Collect_Aggressive.cs b/src/tests/GC/API/GC/Collect_Aggressive.cs new file mode 100644 index 00000000000000..9f9403aa00eaae --- /dev/null +++ b/src/tests/GC/API/GC/Collect_Aggressive.cs @@ -0,0 +1,36 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; + +public class AggressiveCollect +{ + public static int Main(string[] args ) + { + CreateGarbage(); + GC.Collect(2, GCCollectionMode.Aggressive); + // At this point, we should have decommitted the unused regions back to the OS + return 100; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static void CreateGarbage() + { + byte[][] smallGarbage = new byte[2000][]; + + // This will force us to use more than one region in the small object heap + for (int i = 0; i < 2000; i++) + { + // It will roughly span one page + smallGarbage[i] = new byte[4000]; + } + + // This will force us to use more than one region in the large object heap + byte[] largeGarbage = new byte[33 * 1024 * 1024]; + + // This will force us to use more than one region in the pin object heap + byte[] pinnedGarbage = GC.AllocateArray(33 * 1024 * 1024, /* pinned = */true); + } +} diff --git a/src/tests/GC/API/GC/Collect_Aggressive.csproj b/src/tests/GC/API/GC/Collect_Aggressive.csproj new file mode 100644 index 00000000000000..e5837c2b8055ed --- /dev/null +++ b/src/tests/GC/API/GC/Collect_Aggressive.csproj @@ -0,0 +1,13 @@ + + + Exe + 0 + + + + PdbOnly + + + + + From fd8117ed2819bac355dd74fc655a2c6807d9eb18 Mon Sep 17 00:00:00 2001 From: Andrew Au Date: Mon, 23 May 2022 19:23:11 -0700 Subject: [PATCH 2/6] Fix negative tests --- src/libraries/System.Runtime/tests/System/GCTests.cs | 2 +- src/tests/GC/API/GC/Collect_neg.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Runtime/tests/System/GCTests.cs b/src/libraries/System.Runtime/tests/System/GCTests.cs index 4faaa1d94e6ea4..31663d2276468b 100644 --- a/src/libraries/System.Runtime/tests/System/GCTests.cs +++ b/src/libraries/System.Runtime/tests/System/GCTests.cs @@ -69,7 +69,7 @@ public static void Collect_NegativeGenerationCount_ThrowsArgumentOutOfRangeExcep [Theory] [InlineData(GCCollectionMode.Default - 1)] - [InlineData(GCCollectionMode.Optimized + 1)] + [InlineData(GCCollectionMode.Aggressive + 1)] public static void Collection_InvalidCollectionMode_ThrowsArgumentOutOfRangeException(GCCollectionMode mode) { AssertExtensions.Throws("mode", null, () => GC.Collect(2, mode)); diff --git a/src/tests/GC/API/GC/Collect_neg.cs b/src/tests/GC/API/GC/Collect_neg.cs index 06c47ea7adf0e9..979d53016b33bf 100644 --- a/src/tests/GC/API/GC/Collect_neg.cs +++ b/src/tests/GC/API/GC/Collect_neg.cs @@ -8,7 +8,7 @@ public class NegCollect public static int Main() { bool retVal = true; - GCCollectionMode[] invalidInputs = { (GCCollectionMode)(GCCollectionMode.Default - 1), (GCCollectionMode)(GCCollectionMode.Optimized + 1) }; + GCCollectionMode[] invalidInputs = { (GCCollectionMode)(GCCollectionMode.Default - 1), (GCCollectionMode)(GCCollectionMode.Aggressive + 1) }; for (int i = 0; i < invalidInputs.Length; i++) { From 4bc115f65461f5c70dd9528a3de6858d730124e8 Mon Sep 17 00:00:00 2001 From: Andrew Au Date: Tue, 24 May 2022 09:46:18 -0700 Subject: [PATCH 3/6] Comments --- src/libraries/System.Runtime/ref/System.Runtime.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index af367a4bdda082..5cb7053223fd72 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -2562,13 +2562,23 @@ public static void WaitForPendingFinalizers() { } /// The total amount of time paused in GC since the beginning of the process. public static TimeSpan GetTotalPauseDuration() { return TimeSpan.Zero; } } + + /// Specifies the behavior for a forced garbage collection. public enum GCCollectionMode { + /// The default setting for this enumeration, which is currently . Default = 0, + + /// Forces the garbage collection to occur immediately. Forced = 1, + + /// Allows the garbage collector to determine whether the current time is optimal to reclaim objects. Optimized = 2, + + /// Requests that the garbage collector decommit as much memory as possible. Aggressive = 3, } + public readonly partial struct GCGenerationInfo { private readonly int _dummyPrimitive; From 0d16569093ef305f6205046f4916e07cc512cf36 Mon Sep 17 00:00:00 2001 From: Andrew Au Date: Thu, 26 May 2022 09:04:58 -0700 Subject: [PATCH 4/6] Code Review Feedback --- .../src/System/GC.CoreCLR.cs | 15 ++++++-- src/coreclr/gc/gc.cpp | 34 ++++++++++++------ src/coreclr/gc/gcrecord.h | 6 ++-- .../src/System/GC.NativeAot.cs | 15 ++++++-- .../src/Resources/Strings.resx | 9 +++++ src/tests/GC/API/GC/Collect_Aggressive.cs | 36 ++++++++++++++++--- 6 files changed, 92 insertions(+), 23 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs index 2c7716a501723d..45d8a5762e23df 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs @@ -214,9 +214,18 @@ public static void Collect(int generation, GCCollectionMode mode, bool blocking, else if (mode == GCCollectionMode.Aggressive) { iInternalModes |= (int)InternalGCCollectionMode.Aggressive; - // TODO, andrewau, someone intentionally set these flags to false should cause an exception? - blocking = true; - compacting = true; + if (generation != MaxGeneration) + { + throw new ArgumentException(SR.Argument_AggressiveGCRequiresMaxGeneration, nameof(generation)); + } + if (!blocking) + { + throw new ArgumentException(SR.Argument_AggressiveGCRequiresBlocking, nameof(blocking)); + } + if (!compacting) + { + throw new ArgumentException(SR.Argument_AggressiveGCRequiresCompacting, nameof(compacting)); + } } if (compacting) diff --git a/src/coreclr/gc/gc.cpp b/src/coreclr/gc/gc.cpp index 9e1fea7109aa33..e9d40e0bce264f 100644 --- a/src/coreclr/gc/gc.cpp +++ b/src/coreclr/gc/gc.cpp @@ -12305,24 +12305,32 @@ void gc_heap::distribute_free_regions() for (int i = 0; i < n_heaps; i++) { gc_heap* hp = g_heaps[i]; - int hn = i; #else //MULTIPLE_HEAPS { gc_heap* hp = pGenGCHeap; - int hn = 0; #endif //MULTIPLE_HEAPS for (int kind = basic_free_region; kind < count_free_region_kinds; kind++) { global_regions_to_decommit[kind].transfer_regions (&hp->free_regions[kind]); } - while (hp->decommit_step()) - { - } + } + while (decommit_step()) + { + } +#ifdef MULTIPLE_HEAPS + for (int i = 0; i < n_heaps; i++) + { + gc_heap* hp = g_heaps[i]; + int hn = i; +#else //MULTIPLE_HEAPS + { + gc_heap* hp = pGenGCHeap; + int hn = 0; +#endif //MULTIPLE_HEAPS for (int i = 0; i < total_generation_count; i++) { - generation* generation = hp->generation_of(i); - heap_segment* region = generation_start_segment (generation); - region = heap_segment_rw (region); + generation* generation = hp->generation_of (i); + heap_segment* region = heap_segment_rw (generation_start_segment (generation)); while (region != nullptr) { uint8_t* aligned_allocated = align_on_page (heap_segment_allocated (region)); @@ -25083,7 +25091,6 @@ size_t gc_heap::committed_size() total_committed += committed_in_free; #endif //USE_REGIONS - return total_committed; } @@ -40259,13 +40266,20 @@ BOOL gc_heap::decide_on_compacting (int condemned_gen_number, get_gc_data_per_heap()->set_mechanism (gc_heap_compact, compact_last_gc); } - if (settings.reason == reason_induced_compacting || settings.reason == reason_induced_aggressive) + if (settings.reason == reason_induced_compacting) { dprintf (2, ("induced compacting GC")); should_compact = TRUE; get_gc_data_per_heap()->set_mechanism (gc_heap_compact, compact_induced_compacting); } + if (settings.reason == reason_induced_aggressive) + { + dprintf (2, ("aggressive compacting GC")); + should_compact = TRUE; + get_gc_data_per_heap()->set_mechanism (gc_heap_compact, compact_aggressive_compacting); + } + if (settings.reason == reason_pm_full_gc) { assert (condemned_gen_number == max_generation); diff --git a/src/coreclr/gc/gcrecord.h b/src/coreclr/gc/gcrecord.h index 68d0f4dfabe210..7df8d0aca03d77 100644 --- a/src/coreclr/gc/gcrecord.h +++ b/src/coreclr/gc/gcrecord.h @@ -248,7 +248,8 @@ enum gc_heap_compact_reason compact_high_mem_frag = 8, compact_vhigh_mem_frag = 9, compact_no_gc_mode = 10, - max_compact_reasons_count = 11 + compact_aggressive_compacting = 11, + max_compact_reasons_count = 12 }; #ifndef DACCESS_COMPILE @@ -264,7 +265,8 @@ static BOOL gc_heap_compact_reason_mandatory_p[] = FALSE, //compact_high_mem_load = 7, TRUE, //compact_high_mem_frag = 8, TRUE, //compact_vhigh_mem_frag = 9, - TRUE //compact_no_gc_mode = 10 + TRUE, //compact_no_gc_mode = 10, + TRUE //compact_aggressive_compacting = 11 }; static BOOL gc_expand_mechanism_mandatory_p[] = diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/GC.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/GC.NativeAot.cs index 84d1ac939ca3f4..8ac6a38324d56e 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/GC.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/GC.NativeAot.cs @@ -140,9 +140,18 @@ public static void Collect(int generation, GCCollectionMode mode, bool blocking, else if (mode == GCCollectionMode.Aggressive) { iInternalModes |= (int)InternalGCCollectionMode.Aggressive; - // TODO, andrewau, someone intentionally set these flags to false should cause an exception? - blocking = true; - compacting = true; + if (generation != MaxGeneration) + { + throw new ArgumentException(SR.Argument_AggressiveGCRequiresMaxGeneration, nameof(generation)); + } + if (!blocking) + { + throw new ArgumentException(SR.Argument_AggressiveGCRequiresBlocking, nameof(blocking)); + } + if (!compacting) + { + throw new ArgumentException(SR.Argument_AggressiveGCRequiresCompacting, nameof(compacting)); + } } if (compacting) diff --git a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx index b1deeb8c264849..98c61f7eb80539 100644 --- a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx +++ b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx @@ -3529,6 +3529,15 @@ The method was called with a null array argument. + + AggressiveGC requires setting the generation parameter to MaxGeneration + + + AggressiveGC requires setting the blocking parameter to true. + + + AggressiveGC requires setting the compacting parameter to true. + Abstract methods cannot be prepared. diff --git a/src/tests/GC/API/GC/Collect_Aggressive.cs b/src/tests/GC/API/GC/Collect_Aggressive.cs index 9f9403aa00eaae..3d04a8c93d6830 100644 --- a/src/tests/GC/API/GC/Collect_Aggressive.cs +++ b/src/tests/GC/API/GC/Collect_Aggressive.cs @@ -9,14 +9,31 @@ public class AggressiveCollect { public static int Main(string[] args ) { - CreateGarbage(); - GC.Collect(2, GCCollectionMode.Aggressive); - // At this point, we should have decommitted the unused regions back to the OS - return 100; + long before = CreateGarbage(); + GC.Collect(2, GCCollectionMode.Aggressive, blocking: true, compacting: true); + long after = GC.GetGCMemoryInfo().TotalCommittedBytes; + long reclaimed = before - after; + long reclaimedAtLeast = 2000 * 4000; + if (reclaimed < reclaimedAtLeast) + { + // If we reach this case, the aggressive GC is not releasing as much memory as + // we wished, something is wrong. + return 101; + } + else + { + // Doing some extra allocation (and also trigger GC indirectly) here + // should be just fine. + for (int i = 0; i < 10; i++) + { + CreateGarbage(); + } + return 100; + } } [MethodImpl(MethodImplOptions.NoInlining)] - public static void CreateGarbage() + public static long CreateGarbage() { byte[][] smallGarbage = new byte[2000][]; @@ -32,5 +49,14 @@ public static void CreateGarbage() // This will force us to use more than one region in the pin object heap byte[] pinnedGarbage = GC.AllocateArray(33 * 1024 * 1024, /* pinned = */true); + + GC.Collect(2, GCCollectionMode.Forced, blocking: true, compacting: true); + long committed = GC.GetGCMemoryInfo().TotalCommittedBytes; + + GC.KeepAlive(smallGarbage); + GC.KeepAlive(largeGarbage); + GC.KeepAlive(pinnedGarbage); + + return committed; } } From 8f7596adebf9855c190affe70d5c1b670910ff01 Mon Sep 17 00:00:00 2001 From: Andrew Au Date: Sat, 28 May 2022 20:00:06 -0700 Subject: [PATCH 5/6] Disable AggressiveGC test for Mono --- src/tests/GC/API/GC/Collect_Aggressive.csproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tests/GC/API/GC/Collect_Aggressive.csproj b/src/tests/GC/API/GC/Collect_Aggressive.csproj index e5837c2b8055ed..306065392ef021 100644 --- a/src/tests/GC/API/GC/Collect_Aggressive.csproj +++ b/src/tests/GC/API/GC/Collect_Aggressive.csproj @@ -1,6 +1,8 @@ Exe + + true 0 From c8f2c3ac18b1e46a13fc9bb17c56199e52b939a9 Mon Sep 17 00:00:00 2001 From: Andrew Au Date: Sun, 29 May 2022 09:19:12 -0700 Subject: [PATCH 6/6] NITs --- src/coreclr/gc/gc.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/coreclr/gc/gc.cpp b/src/coreclr/gc/gc.cpp index e9d40e0bce264f..a7cccb0d2d88bd 100644 --- a/src/coreclr/gc/gc.cpp +++ b/src/coreclr/gc/gc.cpp @@ -25091,6 +25091,7 @@ size_t gc_heap::committed_size() total_committed += committed_in_free; #endif //USE_REGIONS + return total_committed; }