diff --git a/src/gc.c b/src/gc.c index 15d48f600ed80..77f60bdc9673e 100644 --- a/src/gc.c +++ b/src/gc.c @@ -8,6 +8,7 @@ #ifdef __GLIBC__ #include // for malloc_trim #endif +#include #ifdef __cplusplus extern "C" { @@ -3669,10 +3670,15 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) last_live_bytes = live_bytes; live_bytes += -gc_num.freed + actual_allocd; + // XXX: we've observed that the `live_bytes` was negative in a few cases + // which is not expected. We should investigate this further, but let's just + // cap it to 0 for now. + int64_t live_bytes_for_interval_computation = live_bytes < 0 ? 0 : live_bytes; + if (collection == JL_GC_AUTO) { //If we aren't freeing enough or are seeing lots and lots of pointers let it increase faster if (not_freed_enough || large_frontier) { - int64_t tot = 2 * (live_bytes + actual_allocd) / 3; + int64_t tot = 2 * (live_bytes_for_interval_computation + actual_allocd) / 3; if (gc_num.interval > tot) { gc_num.interval = tot; last_long_collect_interval = tot; @@ -3680,18 +3686,23 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) } // If the current interval is larger than half the live data decrease the interval else { - int64_t half = (live_bytes / 2); + int64_t half = (live_bytes_for_interval_computation / 2); if (gc_num.interval > half) gc_num.interval = half; } // But never go below default - if (gc_num.interval < default_collect_interval) gc_num.interval = default_collect_interval; + if (gc_num.interval < default_collect_interval) + gc_num.interval = default_collect_interval; + // And never go above the upper bound + const int64_t interval_upper_bound = (int64_t)((double)max_total_memory / log2((double)max_total_memory)); + if (gc_num.interval > interval_upper_bound) + gc_num.interval = interval_upper_bound; } - if (gc_num.interval + live_bytes > max_total_memory) { - if (live_bytes < max_total_memory) { - gc_num.interval = max_total_memory - live_bytes; - last_long_collect_interval = max_total_memory - live_bytes; + if (gc_num.interval + live_bytes_for_interval_computation > max_total_memory) { + if (live_bytes_for_interval_computation < max_total_memory) { + gc_num.interval = max_total_memory - live_bytes_for_interval_computation; + last_long_collect_interval = max_total_memory - live_bytes_for_interval_computation; } else { // We can't stay under our goal so let's go back to