@@ -182,6 +182,7 @@ _PyGC_Init(PyInterpreterState *interp)
182182        return  _PyStatus_NO_MEMORY ();
183183    }
184184    gcstate -> heap_size  =  0 ;
185+     gcstate -> prior_heap_size  =  0 ;
185186
186187    return  _PyStatus_OK ();
187188}
@@ -1278,19 +1279,16 @@ gc_list_set_space(PyGC_Head *list, int space)
12781279 * the incremental collector must progress through the old 
12791280 * space faster than objects are added to the old space. 
12801281 * 
1281-  * Each young or incremental collection adds a number of 
1282-  * objects, S (for survivors) to the old space, and 
1283-  * incremental collectors scan I objects from the old space. 
1284-  * I > S must be true. We also want I > S * N to be where 
1285-  * N > 1. Higher values of N mean that the old space is 
1286-  * scanned more rapidly. 
1287-  * The default incremental threshold of 10 translates to 
1288-  * N == 1.4 (1 + 4/threshold) 
1282+  * To do this we maintain a prior heap size, so the 
1283+  * change in heap size can easily be computed. 
1284+  * 
1285+  * Each increment scans twice the delta (if increasing) 
1286+  * plus half the size of the young generation. 
12891287 */ 
12901288
1291- /* Divide  by 10 , so that the default incremental threshold of 10 
1292-  * scans objects at 1% of  the heap size  */ 
1293- #define  SCAN_RATE_DIVISOR  10 
1289+ /* Multiply  by 5 , so that the default incremental threshold of 10 
1290+  * scans objects at half the rate as  the young generation  */ 
1291+ #define  SCAN_RATE_MULTIPLIER  20 
12941292
12951293static  void 
12961294add_stats (GCState  * gcstate , int  gen , struct  gc_collection_stats  * stats )
@@ -1344,7 +1342,6 @@ gc_collect_young(PyThreadState *tstate,
13441342    if  (scale_factor  <  1 ) {
13451343        scale_factor  =  1 ;
13461344    }
1347-     gcstate -> work_to_do  +=  gcstate -> heap_size  / SCAN_RATE_DIVISOR  / scale_factor ;
13481345    add_stats (gcstate , 0 , stats );
13491346}
13501347
@@ -1446,9 +1443,6 @@ gc_collect_increment(PyThreadState *tstate, struct gc_collection_stats *stats)
14461443    if  (scale_factor  <  1 ) {
14471444        scale_factor  =  1 ;
14481445    }
1449-     gc_list_merge (& gcstate -> young .head , & increment );
1450-     gcstate -> young .count  =  0 ;
1451-     gc_list_validate_space (& increment , gcstate -> visited_space );
14521446    Py_ssize_t  increment_size  =  0 ;
14531447    while  (increment_size  <  gcstate -> work_to_do ) {
14541448        if  (gc_list_is_empty (not_visited )) {
@@ -1467,7 +1461,12 @@ gc_collect_increment(PyThreadState *tstate, struct gc_collection_stats *stats)
14671461    gc_list_validate_space (& survivors , gcstate -> visited_space );
14681462    gc_list_merge (& survivors , visited );
14691463    assert (gc_list_is_empty (& increment ));
1470-     gcstate -> work_to_do  +=  gcstate -> heap_size  / SCAN_RATE_DIVISOR  / scale_factor ;
1464+     Py_ssize_t  delta  =  gcstate -> heap_size  -  gcstate -> prior_heap_size ;
1465+     delta  +=  gcstate -> young .threshold  *  SCAN_RATE_MULTIPLIER  / scale_factor ;
1466+     if  (delta  >  0 ) {
1467+         gcstate -> work_to_do  +=  delta ;
1468+     }
1469+     gcstate -> prior_heap_size  =  gcstate -> heap_size ;
14711470    gcstate -> work_to_do  -=  increment_size ;
14721471
14731472    validate_old (gcstate );
@@ -1856,6 +1855,7 @@ _PyGC_Collect(PyThreadState *tstate, int generation, _PyGC_Reason reason)
18561855            gc_collect_young (tstate , & stats );
18571856            break ;
18581857        case  1 :
1858+             gc_collect_young (tstate , & stats );
18591859            gc_collect_increment (tstate , & stats );
18601860            break ;
18611861        case  2 :
0 commit comments