@@ -2250,6 +2250,7 @@ double gc_heap::short_plugs_pad_ratio = 0;
2250
2250
#endif //SHORT_PLUGS
2251
2251
2252
2252
int gc_heap::generation_skip_ratio_threshold = 0;
2253
+ int gc_heap::conserve_mem_setting = 0;
2253
2254
2254
2255
uint64_t gc_heap::suspended_start_time = 0;
2255
2256
uint64_t gc_heap::end_gc_time = 0;
@@ -12571,9 +12572,9 @@ void gc_heap::make_generation (int gen_num, heap_segment* seg, uint8_t* start)
12571
12572
#endif //DOUBLY_LINKED_FL
12572
12573
12573
12574
#ifdef FREE_USAGE_STATS
12574
- memset (gen->gen_free_spaces, 0, sizeof (gen. gen_free_spaces));
12575
- memset (gen->gen_current_pinned_free_spaces, 0, sizeof (gen. gen_current_pinned_free_spaces));
12576
- memset (gen->gen_plugs, 0, sizeof (gen. gen_plugs));
12575
+ memset (gen->gen_free_spaces, 0, sizeof (gen-> gen_free_spaces));
12576
+ memset (gen->gen_current_pinned_free_spaces, 0, sizeof (gen-> gen_current_pinned_free_spaces));
12577
+ memset (gen->gen_plugs, 0, sizeof (gen-> gen_plugs));
12577
12578
#endif //FREE_USAGE_STATS
12578
12579
}
12579
12580
@@ -13171,6 +13172,14 @@ gc_heap::init_semi_shared()
13171
13172
#endif //FEATURE_LOH_COMPACTION
13172
13173
#endif //FEATURE_EVENT_TRACE
13173
13174
13175
+ conserve_mem_setting = (int)GCConfig::GetGCConserveMem();
13176
+ if (conserve_mem_setting < 0)
13177
+ conserve_mem_setting = 0;
13178
+ if (conserve_mem_setting > 9)
13179
+ conserve_mem_setting = 9;
13180
+
13181
+ dprintf (1, ("conserve_mem_setting = %d", conserve_mem_setting));
13182
+
13174
13183
ret = 1;
13175
13184
13176
13185
cleanup:
@@ -17690,7 +17699,6 @@ void gc_heap::init_free_and_plug()
17690
17699
#else
17691
17700
memset (gen->gen_free_spaces, 0, sizeof (gen->gen_free_spaces));
17692
17701
#endif //DOUBLY_LINKED_FL
17693
- memset (gen->gen_plugs_allocated_in_free, 0, sizeof (gen->gen_plugs_allocated_in_free));
17694
17702
memset (gen->gen_plugs, 0, sizeof (gen->gen_plugs));
17695
17703
memset (gen->gen_current_pinned_free_spaces, 0, sizeof (gen->gen_current_pinned_free_spaces));
17696
17704
}
@@ -17708,7 +17716,7 @@ void gc_heap::init_free_and_plug()
17708
17716
17709
17717
void gc_heap::print_free_and_plug (const char* msg)
17710
17718
{
17711
- #if defined( FREE_USAGE_STATS) && defined(SIMPLE_DPRINTF)
17719
+ #ifdef FREE_USAGE_STATS
17712
17720
int older_gen = ((settings.condemned_generation == max_generation) ? max_generation : (settings.condemned_generation + 1));
17713
17721
for (int i = 0; i <= older_gen; i++)
17714
17722
{
@@ -17729,7 +17737,7 @@ void gc_heap::print_free_and_plug (const char* msg)
17729
17737
}
17730
17738
#else
17731
17739
UNREFERENCED_PARAMETER(msg);
17732
- #endif //FREE_USAGE_STATS && SIMPLE_DPRINTF
17740
+ #endif //FREE_USAGE_STATS
17733
17741
}
17734
17742
17735
17743
// replace with allocator::first_suitable_bucket
@@ -17801,8 +17809,8 @@ void gc_heap::add_gen_free (int gen_number, size_t free_size)
17801
17809
(gen->gen_free_spaces[i])++;
17802
17810
if (gen_number == max_generation)
17803
17811
{
17804
- dprintf (3, ("Mb b%d: f+ %Id (%Id->%Id )",
17805
- i, free_size, ( gen->gen_free_spaces[i]).num_items, (gen->gen_free_spaces[i]).total_size ));
17812
+ dprintf (3, ("Mb b%d: f+ %Id (%Id)",
17813
+ i, free_size, gen->gen_free_spaces[i]));
17806
17814
}
17807
17815
#else
17808
17816
UNREFERENCED_PARAMETER(gen_number);
@@ -17824,8 +17832,8 @@ void gc_heap::remove_gen_free (int gen_number, size_t free_size)
17824
17832
(gen->gen_free_spaces[i])--;
17825
17833
if (gen_number == max_generation)
17826
17834
{
17827
- dprintf (3, ("Mb b%d: f- %Id (%Id->%Id )",
17828
- i, free_size, ( gen->gen_free_spaces[i]).num_items, (gen->gen_free_spaces[i]).total_size ));
17835
+ dprintf (3, ("Mb b%d: f- %Id (%Id)",
17836
+ i, free_size, gen->gen_free_spaces[i]));
17829
17837
}
17830
17838
#else
17831
17839
UNREFERENCED_PARAMETER(gen_number);
@@ -19022,6 +19030,37 @@ int gc_heap::joined_generation_to_condemn (BOOL should_evaluate_elevation,
19022
19030
}
19023
19031
}
19024
19032
19033
+ if ((conserve_mem_setting != 0) && (n == max_generation))
19034
+ {
19035
+ float frag_limit = 1.0f - conserve_mem_setting / 10.0f;
19036
+
19037
+ size_t loh_size = get_total_gen_size (loh_generation);
19038
+ size_t gen2_size = get_total_gen_size (max_generation);
19039
+ float loh_frag_ratio = 0.0f;
19040
+ float combined_frag_ratio = 0.0f;
19041
+ if (loh_size != 0)
19042
+ {
19043
+ size_t loh_frag = get_total_gen_fragmentation (loh_generation);
19044
+ size_t gen2_frag = get_total_gen_fragmentation (max_generation);
19045
+ loh_frag_ratio = (float)loh_frag / (float)loh_size;
19046
+ combined_frag_ratio = (float)(gen2_frag + loh_frag) / (float)(gen2_size + loh_size);
19047
+ }
19048
+ if (combined_frag_ratio > frag_limit)
19049
+ {
19050
+ dprintf (GTC_LOG, ("combined frag: %f > limit %f, loh frag: %f", combined_frag_ratio, frag_limit, loh_frag_ratio));
19051
+ gc_data_global.gen_to_condemn_reasons.set_condition (gen_max_high_frag_p);
19052
+
19053
+ n = max_generation;
19054
+ *blocking_collection_p = TRUE;
19055
+ if (loh_frag_ratio > frag_limit)
19056
+ {
19057
+ settings.loh_compaction = TRUE;
19058
+
19059
+ dprintf (GTC_LOG, ("compacting LOH due to GCConserveMem setting"));
19060
+ }
19061
+ }
19062
+ }
19063
+
19025
19064
#ifdef BGC_SERVO_TUNING
19026
19065
if (bgc_tuning::should_trigger_ngc2())
19027
19066
{
@@ -24180,6 +24219,21 @@ size_t gc_heap::get_total_gen_estimated_reclaim (int gen_number)
24180
24219
return total_estimated_reclaim;
24181
24220
}
24182
24221
24222
+ size_t gc_heap::get_total_gen_size (int gen_number)
24223
+ {
24224
+ #ifdef MULTIPLE_HEAPS
24225
+ size_t size = 0;
24226
+ for (int hn = 0; hn < gc_heap::n_heaps; hn++)
24227
+ {
24228
+ gc_heap* hp = gc_heap::g_heaps[hn];
24229
+ size += hp->generation_size (gen_number);
24230
+ }
24231
+ #else
24232
+ size_t size = generation_size (gen_number);
24233
+ #endif //MULTIPLE_HEAPS
24234
+ return size;
24235
+ }
24236
+
24183
24237
size_t gc_heap::committed_size()
24184
24238
{
24185
24239
size_t total_committed = 0;
@@ -26341,7 +26395,7 @@ BOOL gc_heap::plan_loh()
26341
26395
26342
26396
void gc_heap::compact_loh()
26343
26397
{
26344
- assert (loh_compaction_requested() || heap_hard_limit);
26398
+ assert (loh_compaction_requested() || heap_hard_limit || conserve_mem_setting );
26345
26399
26346
26400
#ifdef FEATURE_EVENT_TRACE
26347
26401
uint64_t start_time, end_time;
@@ -38122,6 +38176,19 @@ size_t gc_heap::desired_new_allocation (dynamic_data* dd,
38122
38176
cst = min (1.0f, float (out) / float (dd_begin_data_size (dd)));
38123
38177
38124
38178
f = surv_to_growth (cst, limit, max_limit);
38179
+ if (conserve_mem_setting != 0)
38180
+ {
38181
+ // if this is set, compute a growth factor based on it.
38182
+ // example: a setting of 6 means we have a goal of 60% live data
38183
+ // this means we allow 40% fragmentation
38184
+ // to keep heap size stable, we only use half of that (20%) for new allocation
38185
+ // f is (live data + new allocation)/(live data), so would be (60% + 20%) / 60% or 1.33
38186
+ float f_conserve = ((10.0f / conserve_mem_setting) - 1) * 0.5f + 1.0f;
38187
+
38188
+ // use the smaller one
38189
+ f = min (f, f_conserve);
38190
+ }
38191
+
38125
38192
size_t max_growth_size = (size_t)(max_size / f);
38126
38193
if (current_size >= max_growth_size)
38127
38194
{
@@ -38145,6 +38212,7 @@ size_t gc_heap::desired_new_allocation (dynamic_data* dd,
38145
38212
#ifdef BGC_SERVO_TUNING
38146
38213
!bgc_tuning::fl_tuning_triggered &&
38147
38214
#endif //BGC_SERVO_TUNING
38215
+ (conserve_mem_setting == 0) &&
38148
38216
(dd_fragmentation (dd) > ((size_t)((f-1)*current_size))))
38149
38217
{
38150
38218
//reducing allocation in case of fragmentation
0 commit comments