@@ -9651,7 +9651,7 @@ int gc_heap::grow_brick_card_tables (uint8_t* start,
96519651 dprintf (GC_TABLE_LOG, ("card table: %zx(translated: %zx), seg map: %zx, mark array: %zx",
96529652 (size_t)ct, (size_t)translated_ct, (size_t)new_seg_mapping_table, (size_t)card_table_mark_array (ct)));
96539653
9654- if (hp-> is_bgc_in_progress())
9654+ if (is_bgc_in_progress())
96559655 {
96569656 dprintf (GC_TABLE_LOG, ("new low: %p, new high: %p, latest mark array is %p(translate: %p)",
96579657 saved_g_lowest_address, saved_g_highest_address,
@@ -9778,7 +9778,7 @@ int gc_heap::grow_brick_card_tables (uint8_t* start,
97789778 else
97799779 {
97809780#ifdef BACKGROUND_GC
9781- if (hp-> is_bgc_in_progress())
9781+ if (is_bgc_in_progress())
97829782 {
97839783 dprintf (GC_TABLE_LOG, ("in range new seg %p, mark_array is %p", new_seg, hp->mark_array));
97849784 if (!commit_mark_array_new_seg (hp, new_seg))
@@ -13076,6 +13076,21 @@ void region_free_list::age_free_regions (region_free_list free_lists[count_free_
1307613076 }
1307713077}
1307813078
13079+ size_t region_free_list::get_size_free_regions(int max_age)
13080+ {
13081+ size_t result = 0;
13082+
13083+ for (heap_segment* region = head_free_region; region != nullptr; region = heap_segment_next (region))
13084+ {
13085+ if (heap_segment_age_in_free (region) <= max_age)
13086+ {
13087+ result += get_region_size(region);
13088+ }
13089+ }
13090+
13091+ return result;
13092+ }
13093+
1307913094void region_free_list::print (int hn, const char* msg, int* ages)
1308013095{
1308113096 dprintf (3, ("h%2d PRINTING-------------------------------", hn));
@@ -13371,6 +13386,7 @@ void gc_heap::distribute_free_regions()
1337113386 global_free_huge_regions.transfer_regions (&global_regions_to_decommit[huge_free_region]);
1337213387
1337313388 size_t free_space_in_huge_regions = global_free_huge_regions.get_size_free_regions();
13389+ size_t free_space_in_young_huge_regions = global_free_huge_regions.get_size_free_regions(MIN_AGE_TO_DECOMMIT_HUGE - 1);
1337413390
1337513391 ptrdiff_t num_regions_to_decommit[kind_count];
1337613392 int region_factor[kind_count] = { 1, LARGE_REGION_FACTOR };
@@ -13384,6 +13400,7 @@ void gc_heap::distribute_free_regions()
1338413400#endif //!MULTIPLE_HEAPS
1338513401
1338613402 size_t num_huge_region_units_to_consider[kind_count] = { 0, free_space_in_huge_regions / region_size[large_free_region] };
13403+ size_t num_young_huge_region_units_to_consider[kind_count] = { 0, free_space_in_young_huge_regions / region_size[large_free_region] };
1338713404
1338813405 for (int kind = basic_free_region; kind < kind_count; kind++)
1338913406 {
@@ -13402,9 +13419,22 @@ void gc_heap::distribute_free_regions()
1340213419
1340313420 ptrdiff_t balance = total_num_free_regions[kind] + num_huge_region_units_to_consider[kind] - total_budget_in_region_units[kind];
1340413421
13422+ // Ignore young huge regions if they are contributing to a surplus.
13423+ if (balance > 0)
13424+ {
13425+ if (balance > static_cast<ptrdiff_t>(num_young_huge_region_units_to_consider[kind]))
13426+ {
13427+ balance -= num_young_huge_region_units_to_consider[kind];
13428+ }
13429+ else
13430+ {
13431+ balance = 0;
13432+ }
13433+ }
13434+
1340513435 if (
1340613436#ifdef BACKGROUND_GC
13407- background_running_p() ||
13437+ ( background_running_p() && (settings.condemned_generation != max_generation) ) ||
1340813438#endif
1340913439 (balance < 0))
1341013440 {
@@ -13588,6 +13618,43 @@ void gc_heap::distribute_free_regions()
1358813618#endif //USE_REGIONS
1358913619}
1359013620
13621+ void gc_heap::age_free_regions(const char* label)
13622+ {
13623+ #ifdef USE_REGIONS
13624+ // If we are doing an ephemeral GC as a precursor to a BGC, then we will age all of the region
13625+ // kinds during the ephemeral GC and skip the call to age_free_regions during the BGC itself.
13626+ bool age_all_region_kinds = (settings.condemned_generation == max_generation) || is_bgc_in_progress();
13627+ if (age_all_region_kinds)
13628+ {
13629+ global_free_huge_regions.age_free_regions();
13630+ }
13631+
13632+ #ifdef MULTIPLE_HEAPS
13633+ for (int i = 0; i < gc_heap::n_heaps; i++)
13634+ {
13635+ gc_heap* hp = gc_heap::g_heaps[i];
13636+ #else //MULTIPLE_HEAPS
13637+ {
13638+ gc_heap* hp = pGenGCHeap;
13639+ const int i = 0;
13640+ #endif //MULTIPLE_HEAPS
13641+
13642+ if (age_all_region_kinds)
13643+ {
13644+ // age and print all kinds of free regions
13645+ region_free_list::age_free_regions (hp->free_regions);
13646+ region_free_list::print (hp->free_regions, i, label);
13647+ }
13648+ else
13649+ {
13650+ // age and print only basic free regions
13651+ hp->free_regions[basic_free_region].age_free_regions();
13652+ hp->free_regions[basic_free_region].print (i, label);
13653+ }
13654+ }
13655+ #endif //USE_REGIONS
13656+ }
13657+
1359113658#ifdef WRITE_WATCH
1359213659uint8_t* g_addresses [array_size+2]; // to get around the bug in GetWriteWatch
1359313660
@@ -22765,21 +22832,8 @@ void gc_heap::gc1()
2276522832 for (int i = 0; i < gc_heap::n_heaps; i++)
2276622833 {
2276722834 g_heaps[i]->descr_generations ("END");
22768- #ifdef USE_REGIONS
22769- if (settings.condemned_generation == max_generation)
22770- {
22771- // age and print all kinds of free regions
22772- region_free_list::age_free_regions (g_heaps[i]->free_regions);
22773- region_free_list::print (g_heaps[i]->free_regions, i, "END");
22774- }
22775- else
22776- {
22777- // age and print only basic free regions
22778- g_heaps[i]->free_regions[basic_free_region].age_free_regions();
22779- g_heaps[i]->free_regions[basic_free_region].print (i, "END");
22780- }
22781- #endif //USE_REGIONS
2278222835 }
22836+ age_free_regions ("END");
2278322837
2278422838#ifdef DYNAMIC_HEAP_COUNT
2278522839 update_total_soh_stable_size();
@@ -22819,18 +22873,7 @@ void gc_heap::gc1()
2281922873 compute_gc_and_ephemeral_range (settings.condemned_generation, true);
2282022874 stomp_write_barrier_ephemeral (ephemeral_low, ephemeral_high,
2282122875 map_region_to_generation_skewed, (uint8_t)min_segment_size_shr);
22822- if (settings.condemned_generation == max_generation)
22823- {
22824- // age and print all kinds of free regions
22825- region_free_list::age_free_regions(free_regions);
22826- region_free_list::print(free_regions, 0, "END");
22827- }
22828- else
22829- {
22830- // age and print only basic free regions
22831- free_regions[basic_free_region].age_free_regions();
22832- free_regions[basic_free_region].print (0, "END");
22833- }
22876+ age_free_regions ("END");
2283422877#endif //USE_REGIONS
2283522878
2283622879 update_end_ngc_time();
@@ -37501,7 +37544,15 @@ void gc_heap::allow_fgc()
3750137544
3750237545BOOL gc_heap::is_bgc_in_progress()
3750337546{
37504- return (background_running_p() || (current_bgc_state == bgc_initialized));
37547+ #ifdef MULTIPLE_HEAPS
37548+ // All heaps are changed to/from the bgc_initialized state during the VM suspension at the start of BGC,
37549+ // so checking any heap will work.
37550+ gc_heap* hp = gc_heap::g_heaps[0];
37551+ #else
37552+ gc_heap* hp = pGenGCHeap;
37553+ #endif //MULTIPLE_HEAPS
37554+
37555+ return (background_running_p() || (hp->current_bgc_state == bgc_initialized));
3750537556}
3750637557
3750737558void gc_heap::clear_commit_flag()
@@ -38016,6 +38067,14 @@ void gc_heap::background_mark_phase ()
3801638067 if (bgc_t_join.joined())
3801738068#endif //MULTIPLE_HEAPS
3801838069 {
38070+ // There's no need to distribute a second time if we just did an ephemeral GC, and we don't want to
38071+ // age the free regions twice.
38072+ if (!do_ephemeral_gc_p)
38073+ {
38074+ distribute_free_regions ();
38075+ age_free_regions ("BGC");
38076+ }
38077+
3801938078#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
3802038079 // Resetting write watch for software write watch is pretty fast, much faster than for hardware write watch. Reset
3802138080 // can be done while the runtime is suspended or after the runtime is restarted, the preference was to reset while
0 commit comments