diff --git a/src/gc.c b/src/gc.c index d4af5f443764c..1974796cfa619 100644 --- a/src/gc.c +++ b/src/gc.c @@ -585,12 +585,20 @@ static void gc_sweep_foreign_objs(void) // GC knobs and self-measurement variables static int64_t last_gc_total_bytes = 0; +// max_total_memory is a suggestion. We try very hard to stay +// under this limit, but we will go above it rather than halting. #ifdef _P64 #define default_collect_interval (5600*1024*sizeof(void*)) static size_t max_collect_interval = 1250000000UL; +// Eventually we can expose this to the user/ci. +static uint64_t max_total_memory = (uint64_t) 2 * 1024 * 1024 * 1024 * 1024 * 1024; #else #define default_collect_interval (3200*1024*sizeof(void*)) static size_t max_collect_interval = 500000000UL; +// Work really hard to stay within 2GB +// Alternative is to risk running out of address space +// on 32 bit architectures. +static uint32_t max_total_memory = (uint32_t) 2 * 1024 * 1024 * 1024; #endif // global variables for GC stats @@ -3158,6 +3166,13 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) gc_num.interval = max_collect_interval; } } + + // If the live data outgrows the suggested max_total_memory + // we keep going with minimum intervals and full gcs until + // we either free some space or get an OOM error. + if (live_bytes > max_total_memory) { + sweep_full = 1; + } if (gc_sweep_always_full) { sweep_full = 1; } @@ -3237,6 +3252,17 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) if (gc_num.interval < default_collect_interval) gc_num.interval = default_collect_interval; } + // We need this for 32 bit but will be useful to set limits on 64 bit + if (gc_num.interval + live_bytes > max_total_memory) { + if (live_bytes < max_total_memory) { + gc_num.interval = max_total_memory - live_bytes; + } else { + // We can't stay under our goal so let's go back to + // the minimum interval and hope things get better + gc_num.interval = default_collect_interval; + } + } + gc_time_summary(sweep_full, t_start, gc_end_t, gc_num.freed, live_bytes, gc_num.interval, pause); prev_sweep_full = sweep_full;