diff options
author | Victor Stinner <vstinner@python.org> | 2022-01-22 15:53:30 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-01-22 15:53:30 (GMT) |
commit | 2d03b73cc9c0dada3243eab1373a46dbd98d24a0 (patch) | |
tree | a5540d769b1f1c8e2f05007df3903736b04932a9 /Objects | |
parent | f1c6ae3270913e095d24ae13ecf96f5a32c8c503 (diff) | |
download | cpython-2d03b73cc9c0dada3243eab1373a46dbd98d24a0.zip cpython-2d03b73cc9c0dada3243eab1373a46dbd98d24a0.tar.gz cpython-2d03b73cc9c0dada3243eab1373a46dbd98d24a0.tar.bz2 |
bpo-46417: remove_subclass() clears tp_subclasses (GH-30793)
The remove_subclass() function now deletes the dictionary when
removing the last subclass (if the dictionary becomes empty) to save
memory: set PyTypeObject.tp_subclasses to NULL. remove_subclass() is
called when a type is deallocated.
_PyType_GetSubclasses() no longer holds a reference to tp_subclasses:
its loop cannot modify tp_subclasses.
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/typeobject.c | 24 |
1 files changed, 15 insertions, 9 deletions
diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 2b47afe..b3c305e 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4137,16 +4137,17 @@ _PyType_GetSubclasses(PyTypeObject *self) return NULL; } - // Hold a strong reference to tp_subclasses while iterating on it - PyObject *dict = Py_XNewRef(self->tp_subclasses); - if (dict == NULL) { + PyObject *subclasses = self->tp_subclasses; // borrowed ref + if (subclasses == NULL) { return list; } - assert(PyDict_CheckExact(dict)); + assert(PyDict_CheckExact(subclasses)); + // The loop cannot modify tp_subclasses, there is no need + // to hold a strong reference (use a borrowed reference). Py_ssize_t i = 0; PyObject *ref; // borrowed ref - while (PyDict_Next(dict, &i, NULL, &ref)) { + while (PyDict_Next(subclasses, &i, NULL, &ref)) { assert(PyWeakref_CheckRef(ref)); PyObject *obj = PyWeakref_GET_OBJECT(ref); // borrowed ref if (obj == Py_None) { @@ -4154,12 +4155,10 @@ _PyType_GetSubclasses(PyTypeObject *self) } assert(PyType_Check(obj)); if (PyList_Append(list, obj) < 0) { - Py_CLEAR(list); - goto done; + Py_DECREF(list); + return NULL; } } -done: - Py_DECREF(dict); return list; } @@ -6568,6 +6567,13 @@ remove_subclass(PyTypeObject *base, PyTypeObject *type) PyErr_Clear(); } Py_XDECREF(key); + + if (PyDict_Size(dict) == 0) { + // Delete the dictionary to save memory. _PyStaticType_Dealloc() + // callers also test if tp_subclasses is NULL to check if a static type + // has no subclass. + Py_CLEAR(base->tp_subclasses); + } } static void |