bpo-38379: Don't block collection of unreachable objects when some ob… · python/cpython@466326d (original) (raw)
`@@ -301,8 +301,18 @@ gc_list_size(PyGC_Head *list)
`
301
301
`return n;
`
302
302
`}
`
303
303
``
``
304
`+
/* Walk the list and mark all objects as non-collecting */
`
``
305
`+
static inline void
`
``
306
`+
gc_list_clear_collecting(PyGC_Head *collectable)
`
``
307
`+
{
`
``
308
`+
PyGC_Head *gc;
`
``
309
`+
for (gc = GC_NEXT(collectable); gc != collectable; gc = GC_NEXT(gc)) {
`
``
310
`+
gc_clear_collecting(gc);
`
``
311
`+
}
`
``
312
`+
}
`
``
313
+
304
314
`/* Append objects in a GC list to a Python list.
`
305
``
`-
- Return 0 if all OK, < 0 if error (out of memory for list).
`
``
315
`+
- Return 0 if all OK, < 0 if error (out of memory for list)
`
306
316
` */
`
307
317
`static int
`
308
318
`append_objects(PyObject *py_list, PyGC_Head *gc_list)
`
`@@ -613,6 +623,22 @@ move_legacy_finalizers(PyGC_Head *unreachable, PyGC_Head *finalizers)
`
613
623
` }
`
614
624
`}
`
615
625
``
``
626
`+
static inline void
`
``
627
`+
clear_unreachable_mask(PyGC_Head *unreachable)
`
``
628
`+
{
`
``
629
`+
/* Check that the list head does not have the unreachable bit set */
`
``
630
`+
assert(((uintptr_t)unreachable & NEXT_MASK_UNREACHABLE) == 0);
`
``
631
+
``
632
`+
PyGC_Head *gc, *next;
`
``
633
`+
unreachable->_gc_next &= ~NEXT_MASK_UNREACHABLE;
`
``
634
`+
for (gc = GC_NEXT(unreachable); gc != unreachable; gc = next) {
`
``
635
`+
_PyObject_ASSERT((PyObject*)FROM_GC(gc), gc->_gc_next & NEXT_MASK_UNREACHABLE);
`
``
636
`+
gc->_gc_next &= ~NEXT_MASK_UNREACHABLE;
`
``
637
`+
next = (PyGC_Head*)gc->_gc_next;
`
``
638
`+
}
`
``
639
`+
validate_list(unreachable, PREV_MASK_COLLECTING);
`
``
640
`+
}
`
``
641
+
616
642
`/* A traversal callback for move_legacy_finalizer_reachable. */
`
617
643
`static int
`
618
644
`visit_move(PyObject *op, PyGC_Head *tolist)
`
`@@ -891,36 +917,6 @@ finalize_garbage(PyGC_Head *collectable)
`
891
917
`gc_list_merge(&seen, collectable);
`
892
918
`}
`
893
919
``
894
``
`-
/* Walk the collectable list and check that they are really unreachable
`
895
``
`-
from the outside (some objects could have been resurrected by a
`
896
``
`-
finalizer). */
`
897
``
`-
static int
`
898
``
`-
check_garbage(PyGC_Head *collectable)
`
899
``
`-
{
`
900
``
`-
int ret = 0;
`
901
``
`-
PyGC_Head *gc;
`
902
``
`-
for (gc = GC_NEXT(collectable); gc != collectable; gc = GC_NEXT(gc)) {
`
903
``
`-
// Use gc_refs and break gc_prev again.
`
904
``
`-
gc_set_refs(gc, Py_REFCNT(FROM_GC(gc)));
`
905
``
`-
_PyObject_ASSERT(FROM_GC(gc), gc_get_refs(gc) != 0);
`
906
``
`-
}
`
907
``
`-
subtract_refs(collectable);
`
908
``
`-
PyGC_Head *prev = collectable;
`
909
``
`-
for (gc = GC_NEXT(collectable); gc != collectable; gc = GC_NEXT(gc)) {
`
910
``
`-
_PyObject_ASSERT_WITH_MSG(FROM_GC(gc),
`
911
``
`-
gc_get_refs(gc) >= 0,
`
912
``
`-
"refcount is too small");
`
913
``
`-
if (gc_get_refs(gc) != 0) {
`
914
``
`-
ret = -1;
`
915
``
`-
}
`
916
``
`-
// Restore gc_prev here.
`
917
``
`-
_PyGCHead_SET_PREV(gc, prev);
`
918
``
`-
gc_clear_collecting(gc);
`
919
``
`-
prev = gc;
`
920
``
`-
}
`
921
``
`-
return ret;
`
922
``
`-
}
`
923
``
-
924
920
`/* Break reference cycles by clearing the containers involved. This is
`
925
921
` * tricky business as the lists can be changing and we don't know which
`
926
922
` * objects may be freed. It is possible I screwed something up here.
`
`@@ -958,6 +954,7 @@ delete_garbage(struct _gc_runtime_state *state,
`
958
954
` }
`
959
955
`if (GC_NEXT(collectable) == gc) {
`
960
956
`/* object is still alive, move it, it may die later */
`
``
957
`+
gc_clear_collecting(gc);
`
961
958
`gc_list_move(gc, old);
`
962
959
` }
`
963
960
` }
`
`@@ -1003,6 +1000,87 @@ show_stats_each_generations(struct _gc_runtime_state *state)
`
1003
1000
`buf, gc_list_size(&state->permanent_generation.head));
`
1004
1001
`}
`
1005
1002
``
``
1003
`+
/* Deduce wich objects among "base" are unreachable from outside the list
`
``
1004
`+
and move them to 'unreachable'. The process consist in the following steps:
`
``
1005
+
``
1006
`+
- Copy all reference counts to a different field (gc_prev is used to hold
`
``
1007
`+
this copy to save memory).
`
``
1008
`+
- Traverse all objects in "base" and visit all referred objects using
`
``
1009
`+
"tp_traverse" and for every visited object, substract 1 to the reference
`
``
1010
`+
count (the one that we copied in the previous step). After this step, all
`
``
1011
`+
objects that can be reached directly from outside must have strictly positive
`
``
1012
`+
reference count, while all unreachable objects must have a count of exactly 0.
`
``
1013
`+
- Indentify all unreachable objects (the ones with 0 reference count) and move
`
``
1014
`+
them to the "unreachable" list. This step also needs to move back to "base" all
`
``
1015
`+
objects that were initially marked as unreachable but are referred transitively
`
``
1016
`+
by the reachable objects (the ones with strictly positive reference count).
`
``
1017
+
``
1018
`+
Contracts:
`
``
1019
+
``
1020
`+
- The "base" has to be a valid list with no mask set.
`
``
1021
+
``
1022
`+
- The "unreachable" list must be uninitialized (this function calls
`
``
1023
`+
gc_list_init over 'unreachable').
`
``
1024
+
``
1025
`+
IMPORTANT: This function leaves 'unreachable' with the NEXT_MASK_UNREACHABLE
`
``
1026
`+
flag set but it does not clear it to skip unnecessary iteration. Before the
`
``
1027
`+
flag is cleared (for example, by using 'clear_unreachable_mask' function or
`
``
1028
`+
by a call to 'move_legacy_finalizers'), the 'unreachable' list is not a normal
`
``
1029
`+
list and we can not use most gc_list_* functions for it. */
`
``
1030
`+
static inline void
`
``
1031
`+
deduce_unreachable(PyGC_Head *base, PyGC_Head *unreachable) {
`
``
1032
`+
validate_list(base, 0);
`
``
1033
`+
/* Using ob_refcnt and gc_refs, calculate which objects in the
`
``
1034
`+
- container set are reachable from outside the set (i.e., have a
`
``
1035
`+
- refcount greater than 0 when all the references within the
`
``
1036
`+
- set are taken into account).
`
``
1037
`+
*/
`
``
1038
`+
update_refs(base); // gc_prev is used for gc_refs
`
``
1039
`+
subtract_refs(base);
`
``
1040
+
``
1041
`+
/* Leave everything reachable from outside base in base, and move
`
``
1042
`+
- everything else (in base) to unreachable.
`
``
1043
`+
- NOTE: This used to move the reachable objects into a reachable
`
``
1044
`+
- set instead. But most things usually turn out to be reachable,
`
``
1045
`+
- so it's more efficient to move the unreachable things.
`
``
1046
`+
*/
`
``
1047
`+
gc_list_init(unreachable);
`
``
1048
`+
move_unreachable(base, unreachable); // gc_prev is pointer again
`
``
1049
`+
validate_list(base, 0);
`
``
1050
`+
}
`
``
1051
+
``
1052
`+
/* Handle objects that may have resurrected after a call to 'finalize_garbage', moving
`
``
1053
`+
them to 'old_generation' and placing the rest on 'still_unreachable'.
`
``
1054
+
``
1055
`+
Contracts:
`
``
1056
`+
- After this function 'unreachable' must not be used anymore and 'still_unreachable'
`
``
1057
`+
will contain the objects that did not resurrect.
`
``
1058
+
``
1059
`+
- The "still_unreachable" list must be uninitialized (this function calls
`
``
1060
`+
gc_list_init over 'still_unreachable').
`
``
1061
+
``
1062
`+
IMPORTANT: After a call to this function, the 'still_unreachable' set will have the
`
``
1063
`+
PREV_MARK_COLLECTING set, but the objects in this set are going to be removed so
`
``
1064
`+
we can skip the expense of clearing the flag to avoid extra iteration. */
`
``
1065
`+
static inline void
`
``
1066
`+
handle_resurrected_objects(PyGC_Head unreachable, PyGC_Head still_unreachable,
`
``
1067
`+
PyGC_Head *old_generation)
`
``
1068
`+
{
`
``
1069
`+
// Remove the PREV_MASK_COLLECTING from unreachable
`
``
1070
`+
// to prepare it for a new call to 'deduce_unreachable'
`
``
1071
`+
gc_list_clear_collecting(unreachable);
`
``
1072
+
``
1073
`+
// After the call to deduce_unreachable, the 'still_unreachable' set will
`
``
1074
`+
// have the PREV_MARK_COLLECTING set, but the objects are going to be
`
``
1075
`+
// removed so we can skip the expense of clearing the flag.
`
``
1076
`+
PyGC_Head* resurrected = unreachable;
`
``
1077
`+
deduce_unreachable(resurrected, still_unreachable);
`
``
1078
`+
clear_unreachable_mask(still_unreachable);
`
``
1079
+
``
1080
`+
// Move the resurrected objects to the old generation for future collection.
`
``
1081
`+
gc_list_merge(resurrected, old_generation);
`
``
1082
`+
}
`
``
1083
+
1006
1084
`/* This is the main function. Read this to understand how the
`
1007
1085
` * collection process works. */
`
1008
1086
`static Py_ssize_t
`
`@@ -1045,26 +1123,9 @@ collect(struct _gc_runtime_state *state, int generation,
`
1045
1123
`old = GEN_HEAD(state, generation+1);
`
1046
1124
`else
`
1047
1125
`old = young;
`
1048
``
-
1049
``
`-
validate_list(young, 0);
`
1050
1126
`validate_list(old, 0);
`
1051
``
`-
/* Using ob_refcnt and gc_refs, calculate which objects in the
`
1052
``
`-
- container set are reachable from outside the set (i.e., have a
`
1053
``
`-
- refcount greater than 0 when all the references within the
`
1054
``
`-
- set are taken into account).
`
1055
``
`-
*/
`
1056
``
`-
update_refs(young); // gc_prev is used for gc_refs
`
1057
``
`-
subtract_refs(young);
`
1058
1127
``
1059
``
`-
/* Leave everything reachable from outside young in young, and move
`
1060
``
`-
- everything else (in young) to unreachable.
`
1061
``
`-
- NOTE: This used to move the reachable objects into a reachable
`
1062
``
`-
- set instead. But most things usually turn out to be reachable,
`
1063
``
`-
- so it's more efficient to move the unreachable things.
`
1064
``
`-
*/
`
1065
``
`-
gc_list_init(&unreachable);
`
1066
``
`-
move_unreachable(young, &unreachable); // gc_prev is pointer again
`
1067
``
`-
validate_list(young, 0);
`
``
1128
`+
deduce_unreachable(young, &unreachable);
`
1068
1129
``
1069
1130
`untrack_tuples(young);
`
1070
1131
`/* Move reachable objects to next generation. */
`
`@@ -1114,17 +1175,18 @@ collect(struct _gc_runtime_state *state, int generation,
`
1114
1175
`/* Call tp_finalize on objects which have one. */
`
1115
1176
`finalize_garbage(&unreachable);
`
1116
1177
``
1117
``
`-
if (check_garbage(&unreachable)) { // clear PREV_MASK_COLLECTING here
`
1118
``
`-
gc_list_merge(&unreachable, old);
`
1119
``
`-
}
`
1120
``
`-
else {
`
1121
``
`-
/* Call tp_clear on objects in the unreachable set. This will cause
`
1122
``
`-
- the reference cycles to be broken. It may also cause some objects
`
1123
``
`-
- in finalizers to be freed.
`
1124
``
`-
*/
`
1125
``
`-
m += gc_list_size(&unreachable);
`
1126
``
`-
delete_garbage(state, &unreachable, old);
`
1127
``
`-
}
`
``
1178
`+
/* Handle any objects that may have resurrected after the call
`
``
1179
`+
- to 'finalize_garbage' and continue the collection with the
`
``
1180
`+
- objects that are still unreachable */
`
``
1181
`+
PyGC_Head final_unreachable;
`
``
1182
`+
handle_resurrected_objects(&unreachable, &final_unreachable, old);
`
``
1183
+
``
1184
`+
/* Call tp_clear on objects in the final_unreachable set. This will cause
`
``
1185
`+
- the reference cycles to be broken. It may also cause some objects
`
``
1186
`+
- in finalizers to be freed.
`
``
1187
`+
*/
`
``
1188
`+
m += gc_list_size(&final_unreachable);
`
``
1189
`+
delete_garbage(state, &final_unreachable, old);
`
1128
1190
``
1129
1191
`/* Collect statistics on uncollectable objects found and print
`
1130
1192
` * debugging information. */
`