@@ -195,7 +195,6 @@ jl_gc_num_t gc_num = {0};
195195static size_t last_long_collect_interval ;
196196int gc_n_threads ;
197197jl_ptls_t * gc_all_tls_states ;
198- int next_sweep_full = 0 ;
199198const uint64_t _jl_buff_tag [3 ] = {0x4eadc0004eadc000ull , 0x4eadc0004eadc000ull , 0x4eadc0004eadc000ull }; // aka 0xHEADER00
200199JL_DLLEXPORT uintptr_t jl_get_buff_tag (void )
201200{
@@ -695,10 +694,8 @@ static const size_t max_collect_interval = 500000000UL;
695694// Work really hard to stay within 2GB
696695// Alternative is to risk running out of address space
697696// on 32 bit architectures.
698- #define MAX32HEAP 1536 * 1024 * 1024
699- static memsize_t max_total_memory = (memsize_t ) MAX32HEAP ;
697+ static memsize_t max_total_memory = (memsize_t ) 2 * 1024 * 1024 * 1024 ;
700698#endif
701- static uint64_t gc_end_time = 0 ;
702699// global variables for GC stats
703700
704701// Resetting the object to a young object, this is used when marking the
@@ -751,14 +748,12 @@ static int64_t scanned_bytes; // young bytes scanned while marking
751748static int64_t perm_scanned_bytes ; // old bytes scanned while marking
752749int prev_sweep_full = 1 ;
753750int current_sweep_full = 0 ;
754- int under_pressure = 0 ;
755751
756752// Full collection heuristics
757753static int64_t live_bytes = 0 ;
758754static int64_t promoted_bytes = 0 ;
759- static int64_t last_full_live = 0 ; // live_bytes after last full collection
760755static int64_t last_live_bytes = 0 ; // live_bytes at last collection
761- static int64_t grown_heap_age = 0 ; // # of collects since live_bytes grew and remained
756+ static int64_t t_start = 0 ; // Time GC starts;
762757#ifdef __GLIBC__
763758// maxrss at last malloc_trim
764759static int64_t last_trim_maxrss = 0 ;
@@ -3332,11 +3327,6 @@ JL_DLLEXPORT int64_t jl_gc_live_bytes(void)
33323327 return live_bytes ;
33333328}
33343329
3335- double jl_gc_smooth (uint64_t old_val , uint64_t new_val , double factor )
3336- {
3337- return factor * old_val + (1.0 - factor ) * new_val ;
3338- }
3339-
33403330size_t jl_maxrss (void );
33413331
33423332// Only one thread should be running in this function
@@ -3453,6 +3443,7 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
34533443 int64_t estimate_freed = live_sz_ub - live_sz_est ;
34543444
34553445 gc_verify (ptls );
3446+
34563447 gc_stats_all_pool ();
34573448 gc_stats_big_obj ();
34583449 objprofile_printall ();
@@ -3469,46 +3460,34 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
34693460 if (ptls2 != NULL )
34703461 nptr += ptls2 -> heap .remset_nptr ;
34713462 }
3472- int large_frontier = nptr * sizeof (void * ) >= default_collect_interval ; // many pointers in the intergen frontier => "quick" mark is not quick
3473- // trigger a full collection if the number of live bytes doubles since the last full
3474- // collection and then remains at least that high for a while.
3475- if (grown_heap_age == 0 ) {
3476- if (live_bytes > 2 * last_full_live )
3477- grown_heap_age = 1 ;
3478- }
3479- else if (live_bytes >= last_live_bytes ) {
3480- grown_heap_age ++ ;
3481- }
3463+
3464+ // many pointers in the intergen frontier => "quick" mark is not quick
3465+ int large_frontier = nptr * sizeof (void * ) >= default_collect_interval ;
34823466 int sweep_full = 0 ;
34833467 int recollect = 0 ;
3484- if ((large_frontier ||
3485- ((not_freed_enough || promoted_bytes >= gc_num .interval ) &&
3486- (promoted_bytes >= default_collect_interval || prev_sweep_full )) ||
3487- grown_heap_age > 1 ) && gc_num .pause > 1 ) {
3488- sweep_full = 1 ;
3489- }
3468+
34903469 // update heuristics only if this GC was automatically triggered
34913470 if (collection == JL_GC_AUTO ) {
3492- if (sweep_full ) {
3493- if (large_frontier )
3494- gc_num .interval = last_long_collect_interval ;
3495- if (not_freed_enough || large_frontier ) {
3496- if (gc_num .interval <= 2 * (max_collect_interval /5 )) {
3497- gc_num .interval = 5 * (gc_num .interval / 2 );
3498- }
3499- }
3500- last_long_collect_interval = gc_num .interval ;
3471+ if (large_frontier ) {
3472+ sweep_full = 1 ;
3473+ gc_num .interval = last_long_collect_interval ;
35013474 }
3502- else {
3503- // reset interval to default, or at least half of live_bytes
3504- int64_t half = live_bytes /2 ;
3505- if (default_collect_interval < half && half <= max_collect_interval )
3506- gc_num .interval = half ;
3507- else
3508- gc_num .interval = default_collect_interval ;
3475+ if (not_freed_enough || large_frontier ) {
3476+ gc_num .interval = gc_num .interval * 2 ;
35093477 }
3510- }
35113478
3479+ size_t maxmem = 0 ;
3480+ #ifdef _P64
3481+ // on a big memory machine, increase max_collect_interval to totalmem / nthreads / 2
3482+ maxmem = total_mem / (gc_n_threads - jl_n_gcthreads ) / 2 ;
3483+ #endif
3484+ if (maxmem < max_collect_interval )
3485+ maxmem = max_collect_interval ;
3486+ if (gc_num .interval > maxmem ) {
3487+ sweep_full = 1 ;
3488+ gc_num .interval = maxmem ;
3489+ }
3490+ }
35123491
35133492 // If the live data outgrows the suggested max_total_memory
35143493 // we keep going with full gcs until we either free some space or get an OOM error.
@@ -3528,6 +3507,7 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
35283507 // on the first collection after sweep_full, and the current scan
35293508 perm_scanned_bytes = 0 ;
35303509 promoted_bytes = 0 ;
3510+ last_long_collect_interval = gc_num .interval ;
35313511 }
35323512 scanned_bytes = 0 ;
35333513 // 6. start sweeping
@@ -3556,7 +3536,7 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
35563536
35573537 JL_PROBE_GC_SWEEP_END ();
35583538
3559- gc_end_time = jl_hrtime ();
3539+ uint64_t gc_end_time = jl_hrtime ();
35603540 uint64_t pause = gc_end_time - gc_start_time ;
35613541 uint64_t sweep_time = gc_end_time - start_sweep_time ;
35623542 gc_num .total_sweep_time += sweep_time ;
@@ -3613,18 +3593,48 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
36133593 gc_num .allocd = 0 ;
36143594 last_live_bytes = live_bytes ;
36153595 live_bytes += - gc_num .freed + actual_allocd ;
3616- jl_timing_counter_dec (JL_TIMING_COUNTER_HeapSize , gc_num .freed );
3596+
3597+ if (collection == JL_GC_AUTO ) {
3598+ //If we aren't freeing enough or are seeing lots and lots of pointers let it increase faster
3599+ if (!not_freed_enough || large_frontier ) {
3600+ int64_t tot = 2 * (live_bytes + actual_allocd ) / 3 ;
3601+ if (gc_num .interval > tot ) {
3602+ gc_num .interval = tot ;
3603+ last_long_collect_interval = tot ;
3604+ }
3605+ }
3606+ // If the current interval is larger than half the live data decrease the interval
3607+ else {
3608+ int64_t half = (live_bytes / 2 );
3609+ if (gc_num .interval > half )
3610+ gc_num .interval = half ;
3611+ }
3612+ // But never go below default
3613+ if (gc_num .interval < default_collect_interval ) gc_num .interval = default_collect_interval ;
3614+ }
3615+
3616+ if (gc_num .interval + live_bytes > max_total_memory ) {
3617+ if (live_bytes < max_total_memory ) {
3618+ gc_num .interval = max_total_memory - live_bytes ;
3619+ last_long_collect_interval = max_total_memory - live_bytes ;
3620+ }
3621+ else {
3622+ // We can't stay under our goal so let's go back to
3623+ // the minimum interval and hope things get better
3624+ under_memory_pressure = 1 ;
3625+ gc_num .interval = default_collect_interval ;
3626+ }
3627+ }
3628+
36173629 gc_time_summary (sweep_full , t_start , gc_end_time , gc_num .freed ,
36183630 live_bytes , gc_num .interval , pause ,
36193631 gc_num .time_to_safepoint ,
36203632 gc_num .mark_time , gc_num .sweep_time );
3621- if (prev_sweep_full ) {
3622- last_full_live = live_bytes ;
3623- grown_heap_age = 0 ;
3624- }
3633+
36253634 prev_sweep_full = sweep_full ;
36263635 gc_num .pause += !recollect ;
36273636 gc_num .total_time += pause ;
3637+ gc_num .allocd = 0 ;
36283638 gc_num .freed = 0 ;
36293639 if (pause > gc_num .max_pause ) {
36303640 gc_num .max_pause = pause ;
@@ -3826,21 +3836,25 @@ void jl_gc_init(void)
38263836 total_mem = uv_get_total_memory ();
38273837 uint64_t constrained_mem = uv_get_constrained_memory ();
38283838 if (constrained_mem > 0 && constrained_mem < total_mem )
3829- jl_gc_set_max_memory (constrained_mem - 250 * 1024 * 1024 ); // LLVM + other libraries need some amount of memory
3839+ total_mem = constrained_mem ;
3840+ double percent ;
3841+ if (total_mem < 128e9 )
3842+ percent = total_mem * 2.34375e-12 + 0.6 ; // 60% at 0 gigs and 90% at 128 to not
3843+ else // overcommit too much on memory contrained devices
3844+ percent = 0.9 ;
3845+ max_total_memory = total_mem * percent ;
38303846#endif
38313847 if (jl_options .heap_size_hint )
38323848 jl_gc_set_max_memory (jl_options .heap_size_hint - 250 * 1024 * 1024 );
3849+
3850+ t_start = jl_hrtime ();
38333851}
38343852
38353853JL_DLLEXPORT void jl_gc_set_max_memory (uint64_t max_mem )
38363854{
38373855 if (max_mem > 0
38383856 && max_mem < (uint64_t )1 << (sizeof (memsize_t ) * 8 - 1 )) {
3839- #ifdef _P64
38403857 max_total_memory = max_mem ;
3841- #else
3842- max_total_memory = max_mem < MAX32HEAP ? max_mem : MAX32HEAP ;
3843- #endif
38443858 }
38453859}
38463860
0 commit comments