diff options
Diffstat (limited to 'Python')
-rw-r--r-- | Python/gc.c | 17 | ||||
-rw-r--r-- | Python/gc_free_threading.c | 32 | ||||
-rw-r--r-- | Python/gc_gil.c | 23 | ||||
-rw-r--r-- | Python/pylifecycle.c | 5 | ||||
-rw-r--r-- | Python/pystate.c | 11 |
5 files changed, 71 insertions, 17 deletions
diff --git a/Python/gc.c b/Python/gc.c index f47c74f..9f9a755 100644 --- a/Python/gc.c +++ b/Python/gc.c @@ -1019,21 +1019,6 @@ delete_garbage(PyThreadState *tstate, GCState *gcstate, } } -/* Clear all free lists - * All free lists are cleared during the collection of the highest generation. - * Allocated items in the free list may keep a pymalloc arena occupied. - * Clearing the free lists may give back memory to the OS earlier. - */ -static void -clear_freelists(PyInterpreterState *interp) -{ - _PyTuple_ClearFreeList(interp); - _PyFloat_ClearFreeList(interp); - _PyList_ClearFreeList(interp); - _PyDict_ClearFreeList(interp); - _PyAsyncGen_ClearFreeLists(interp); - _PyContext_ClearFreeList(interp); -} // Show stats for objects in each generations static void @@ -1449,7 +1434,7 @@ gc_collect_main(PyThreadState *tstate, int generation, _PyGC_Reason reason) /* Clear free list only during the collection of the highest * generation */ if (generation == NUM_GENERATIONS-1) { - clear_freelists(tstate->interp); + _PyGC_ClearAllFreeLists(tstate->interp); } if (_PyErr_Occurred(tstate)) { diff --git a/Python/gc_free_threading.c b/Python/gc_free_threading.c new file mode 100644 index 0000000..aea2728 --- /dev/null +++ b/Python/gc_free_threading.c @@ -0,0 +1,32 @@ +#include "Python.h" +#include "pycore_pystate.h" // _PyFreeListState_GET() +#include "pycore_tstate.h" // _PyThreadStateImpl + +#ifdef Py_GIL_DISABLED + +/* Clear all free lists + * All free lists are cleared during the collection of the highest generation. + * Allocated items in the free list may keep a pymalloc arena occupied. + * Clearing the free lists may give back memory to the OS earlier. + * Free-threading version: Since freelists are managed per thread, + * GC should clear all freelists by traversing all threads. + */ +void +_PyGC_ClearAllFreeLists(PyInterpreterState *interp) +{ + _PyTuple_ClearFreeList(interp); + _PyFloat_ClearFreeList(interp); + _PyDict_ClearFreeList(interp); + _PyAsyncGen_ClearFreeLists(interp); + _PyContext_ClearFreeList(interp); + + HEAD_LOCK(&_PyRuntime); + _PyThreadStateImpl *tstate = (_PyThreadStateImpl *)interp->threads.head; + while (tstate != NULL) { + _Py_ClearFreeLists(&tstate->freelist_state, 0); + tstate = (_PyThreadStateImpl *)tstate->base.next; + } + HEAD_UNLOCK(&_PyRuntime); +} + +#endif diff --git a/Python/gc_gil.c b/Python/gc_gil.c new file mode 100644 index 0000000..b0961cd --- /dev/null +++ b/Python/gc_gil.c @@ -0,0 +1,23 @@ +#include "Python.h" +#include "pycore_pystate.h" // _Py_ClearFreeLists() + +#ifndef Py_GIL_DISABLED + +/* Clear all free lists + * All free lists are cleared during the collection of the highest generation. + * Allocated items in the free list may keep a pymalloc arena occupied. + * Clearing the free lists may give back memory to the OS earlier. + */ +void +_PyGC_ClearAllFreeLists(PyInterpreterState *interp) +{ + _PyTuple_ClearFreeList(interp); + _PyFloat_ClearFreeList(interp); + _PyDict_ClearFreeList(interp); + _PyAsyncGen_ClearFreeLists(interp); + _PyContext_ClearFreeList(interp); + + _Py_ClearFreeLists(&interp->freelist_state, 0); +} + +#endif diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 1d8af26..bd6475f 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1752,13 +1752,16 @@ finalize_interp_types(PyInterpreterState *interp) _PyUnicode_ClearInterned(interp); _PyDict_Fini(interp); - _PyList_Fini(interp); _PyTuple_Fini(interp); _PySlice_Fini(interp); _PyUnicode_Fini(interp); _PyFloat_Fini(interp); + + _PyFreeListState *state = _PyFreeListState_GET(); + _PyList_Fini(state); + #ifdef Py_DEBUG _PyStaticObjects_CheckRefcnt(interp); #endif diff --git a/Python/pystate.c b/Python/pystate.c index 21f16b7..ddd57f7 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1456,6 +1456,12 @@ clear_datastack(PyThreadState *tstate) } void +_Py_ClearFreeLists(_PyFreeListState *state, int is_finalization) +{ + _PyList_ClearFreeList(state, is_finalization); +} + +void PyThreadState_Clear(PyThreadState *tstate) { assert(tstate->_status.initialized && !tstate->_status.cleared); @@ -1537,6 +1543,11 @@ PyThreadState_Clear(PyThreadState *tstate) // don't call _PyInterpreterState_SetNotRunningMain() yet. tstate->on_delete(tstate->on_delete_data); } +#ifdef Py_GIL_DISABLED + // Each thread should clear own freelists in free-threading builds. + _PyFreeListState *freelist_state = &((_PyThreadStateImpl*)tstate)->freelist_state; + _Py_ClearFreeLists(freelist_state, 0); +#endif _PyThreadState_ClearMimallocHeaps(tstate); |