incremental GC: tune departure from incremental mode

At the completion of an incremental major GC, if incremental
mode wasn't requested recently, schedule an immediate major
GC to reduce the heap back to its normal footprint.
This commit is contained in:
Matthew Flatt 2015-12-19 10:17:39 -07:00
parent ddaffc8248
commit 6957780cd5
2 changed files with 23 additions and 9 deletions

View File

@ -3666,7 +3666,10 @@ void GC_request_incremental_mode(void)
{
NewGC *gc = GC_get_GC();
gc->incremental_requested = 1;
/* The request will expire gradually, so that an extra major GC will
be triggered if incremental mode hasn't been requested recently
enough: */
gc->incremental_requested = 8;
}
void GC_set_incremental_mode(int on)
@ -6091,7 +6094,7 @@ static void garbage_collect(NewGC *gc, int force_full, int no_full, int switchin
uintptr_t old_gen0;
uintptr_t old_mem_allocated;
int next_gc_full;
int do_incremental = 0, check_inc_repair;
int do_incremental = 0, had_started_incremental, check_inc_repair;
old_mem_use = gc->memory_in_use; /* includes gc->phantom_count */
old_gen0 = gen0_size_in_use(gc) + gc->gen0_phantom_count;
@ -6114,7 +6117,7 @@ static void garbage_collect(NewGC *gc, int force_full, int no_full, int switchin
fraction of the actual use by live data: */
|| (gc->memory_in_use > (FULL_COLLECTION_SIZE_RATIO
* gc->last_full_mem_use
* (gc->started_incremental
* (gc->incremental_requested
? INCREMENTAL_EXTRA_SIZE_RATIO
: 1)))
/* Just in case, for a full GC every so often, unless
@ -6134,7 +6137,7 @@ static void garbage_collect(NewGC *gc, int force_full, int no_full, int switchin
return;
next_gc_full = (gc->gc_full
&& !gc->started_incremental
&& !gc->incremental_requested
&& !gc->full_needed_for_finalization);
if (gc->full_needed_for_finalization && gc->gc_full)
@ -6178,7 +6181,8 @@ static void garbage_collect(NewGC *gc, int force_full, int no_full, int switchin
if (do_incremental)
gc->started_incremental = 1;
gc->incremental_requested = 0;
if (gc->incremental_requested)
--gc->incremental_requested;
gc->mark_gen1 = (gc->gc_full || gc->started_incremental) && !gc->all_marked_incremental;
gc->check_gen1 = gc->gc_full && !gc->all_marked_incremental;
@ -6384,12 +6388,14 @@ static void garbage_collect(NewGC *gc, int force_full, int no_full, int switchin
else
gc->since_last_full += 10;
}
had_started_incremental = gc->started_incremental;
if (gc->gc_full) {
gc->last_full_mem_use = gc->memory_in_use;
gc->started_incremental = 0;
gc->all_marked_incremental = 0;
gc->finished_incremental = 0;
gc->inc_prop_count = 0;
gc->incremental_requested = 0; /* request expires completely after a full GC */
}
/* inform the system (if it wants us to) that we're done with collection */
@ -6401,7 +6407,7 @@ static void garbage_collect(NewGC *gc, int force_full, int no_full, int switchin
is_master = (gc == MASTERGC);
#endif
park_for_inform_callback(gc);
gc->GC_collect_inform_callback(is_master, gc->gc_full, gc->started_incremental,
gc->GC_collect_inform_callback(is_master, gc->gc_full, had_started_incremental,
/* original memory use: */
old_mem_use + old_gen0,
/* new memory use; gen0_phantom_count can be non-zero due to
@ -6435,8 +6441,16 @@ static void garbage_collect(NewGC *gc, int force_full, int no_full, int switchin
if (gc->gc_full)
merge_run_queues(gc);
if (!gc->run_queue)
next_gc_full = 0;
if (!gc->run_queue) {
if (had_started_incremental) {
/* Keep next_gc_full, if it's set, because that means incremental
mode wasn't requested recently, even through we're wrapping up
an incremental GC; another major GC is likely to reclaim more
memory, reduce fragentation, and generally improve heap
health */
} else
next_gc_full = 0;
}
/* Run any queued finalizers, EXCEPT in the case where this
collection was triggered during the execution of a finalizer.

View File

@ -228,7 +228,7 @@ typedef struct NewGC {
unsigned char inc_gen1 :1; /* during incremental marking of old generation */
unsigned char fnl_gen1 :1; /* during incremental finalization of old generation */
unsigned char during_backpointer :1;
unsigned char incremental_requested :1;
unsigned char incremental_requested :4; /* counts down to track recentness of request */
unsigned char high_fragmentation :1;
unsigned char unprotected_page :1;