#endif //SHORT_PLUGS
int gc_heap::generation_skip_ratio_threshold = 0;
+int gc_heap::conserve_mem_setting = 0;
uint64_t gc_heap::suspended_start_time = 0;
uint64_t gc_heap::end_gc_time = 0;
#endif //DOUBLY_LINKED_FL
#ifdef FREE_USAGE_STATS
- memset (gen->gen_free_spaces, 0, sizeof (gen.gen_free_spaces));
- memset (gen->gen_current_pinned_free_spaces, 0, sizeof (gen.gen_current_pinned_free_spaces));
- memset (gen->gen_plugs, 0, sizeof (gen.gen_plugs));
+ memset (gen->gen_free_spaces, 0, sizeof (gen->gen_free_spaces));
+ memset (gen->gen_current_pinned_free_spaces, 0, sizeof (gen->gen_current_pinned_free_spaces));
+ memset (gen->gen_plugs, 0, sizeof (gen->gen_plugs));
#endif //FREE_USAGE_STATS
}
#endif //FEATURE_LOH_COMPACTION
#endif //FEATURE_EVENT_TRACE
+ conserve_mem_setting = (int)GCConfig::GetGCConserveMem();
+ if (conserve_mem_setting < 0)
+ conserve_mem_setting = 0;
+ if (conserve_mem_setting > 9)
+ conserve_mem_setting = 9;
+
+ dprintf (1, ("conserve_mem_setting = %d", conserve_mem_setting));
+
ret = 1;
cleanup:
#else
memset (gen->gen_free_spaces, 0, sizeof (gen->gen_free_spaces));
#endif //DOUBLY_LINKED_FL
- memset (gen->gen_plugs_allocated_in_free, 0, sizeof (gen->gen_plugs_allocated_in_free));
memset (gen->gen_plugs, 0, sizeof (gen->gen_plugs));
memset (gen->gen_current_pinned_free_spaces, 0, sizeof (gen->gen_current_pinned_free_spaces));
}
void gc_heap::print_free_and_plug (const char* msg)
{
-#if defined(FREE_USAGE_STATS) && defined(SIMPLE_DPRINTF)
+#ifdef FREE_USAGE_STATS
int older_gen = ((settings.condemned_generation == max_generation) ? max_generation : (settings.condemned_generation + 1));
for (int i = 0; i <= older_gen; i++)
{
}
#else
UNREFERENCED_PARAMETER(msg);
-#endif //FREE_USAGE_STATS && SIMPLE_DPRINTF
+#endif //FREE_USAGE_STATS
}
// replace with allocator::first_suitable_bucket
(gen->gen_free_spaces[i])++;
if (gen_number == max_generation)
{
- dprintf (3, ("Mb b%d: f+ %Id (%Id->%Id)",
- i, free_size, (gen->gen_free_spaces[i]).num_items, (gen->gen_free_spaces[i]).total_size));
+ dprintf (3, ("Mb b%d: f+ %Id (%Id)",
+ i, free_size, gen->gen_free_spaces[i]));
}
#else
UNREFERENCED_PARAMETER(gen_number);
(gen->gen_free_spaces[i])--;
if (gen_number == max_generation)
{
- dprintf (3, ("Mb b%d: f- %Id (%Id->%Id)",
- i, free_size, (gen->gen_free_spaces[i]).num_items, (gen->gen_free_spaces[i]).total_size));
+ dprintf (3, ("Mb b%d: f- %Id (%Id)",
+ i, free_size, gen->gen_free_spaces[i]));
}
#else
UNREFERENCED_PARAMETER(gen_number);
}
}
+ if ((conserve_mem_setting != 0) && (n == max_generation))
+ {
+ float frag_limit = 1.0f - conserve_mem_setting / 10.0f;
+
+ size_t loh_size = get_total_gen_size (loh_generation);
+ size_t gen2_size = get_total_gen_size (max_generation);
+ float loh_frag_ratio = 0.0f;
+ float combined_frag_ratio = 0.0f;
+ if (loh_size != 0)
+ {
+ size_t loh_frag = get_total_gen_fragmentation (loh_generation);
+ size_t gen2_frag = get_total_gen_fragmentation (max_generation);
+ loh_frag_ratio = (float)loh_frag / (float)loh_size;
+ combined_frag_ratio = (float)(gen2_frag + loh_frag) / (float)(gen2_size + loh_size);
+ }
+ if (combined_frag_ratio > frag_limit)
+ {
+ dprintf (GTC_LOG, ("combined frag: %f > limit %f, loh frag: %f", combined_frag_ratio, frag_limit, loh_frag_ratio));
+ gc_data_global.gen_to_condemn_reasons.set_condition (gen_max_high_frag_p);
+
+ n = max_generation;
+ *blocking_collection_p = TRUE;
+ if (loh_frag_ratio > frag_limit)
+ {
+ settings.loh_compaction = TRUE;
+
+ dprintf (GTC_LOG, ("compacting LOH due to GCConserveMem setting"));
+ }
+ }
+ }
+
#ifdef BGC_SERVO_TUNING
if (bgc_tuning::should_trigger_ngc2())
{
return total_estimated_reclaim;
}
+size_t gc_heap::get_total_gen_size (int gen_number)
+{
+#ifdef MULTIPLE_HEAPS
+ size_t size = 0;
+ for (int hn = 0; hn < gc_heap::n_heaps; hn++)
+ {
+ gc_heap* hp = gc_heap::g_heaps[hn];
+ size += hp->generation_size (gen_number);
+ }
+#else
+ size_t size = generation_size (gen_number);
+#endif //MULTIPLE_HEAPS
+ return size;
+}
+
size_t gc_heap::committed_size()
{
size_t total_committed = 0;
void gc_heap::compact_loh()
{
- assert (loh_compaction_requested() || heap_hard_limit);
+ assert (loh_compaction_requested() || heap_hard_limit || conserve_mem_setting);
#ifdef FEATURE_EVENT_TRACE
uint64_t start_time, end_time;
cst = min (1.0f, float (out) / float (dd_begin_data_size (dd)));
f = surv_to_growth (cst, limit, max_limit);
+ if (conserve_mem_setting != 0)
+ {
+ // if this is set, compute a growth factor based on it.
+ // example: a setting of 6 means we have a goal of 60% live data
+ // this means we allow 40% fragmentation
+ // to keep heap size stable, we only use half of that (20%) for new allocation
+ // f is (live data + new allocation)/(live data), so would be (60% + 20%) / 60% or 1.33
+ float f_conserve = ((10.0f / conserve_mem_setting) - 1) * 0.5f + 1.0f;
+
+ // use the smaller one
+ f = min (f, f_conserve);
+ }
+
size_t max_growth_size = (size_t)(max_size / f);
if (current_size >= max_growth_size)
{
#ifdef BGC_SERVO_TUNING
!bgc_tuning::fl_tuning_triggered &&
#endif //BGC_SERVO_TUNING
+ (conserve_mem_setting == 0) &&
(dd_fragmentation (dd) > ((size_t)((f-1)*current_size))))
{
//reducing allocation in case of fragmentation