diff options
author | Victor Stinner <vstinner@python.org> | 2020-06-05 00:05:41 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-06-05 00:05:41 (GMT) |
commit | 88ec9190105c9b03f49aaef601ce02b242a75273 (patch) | |
tree | 699bea45830306ef5cd9943138a8c03d846e33d3 /Objects/listobject.c | |
parent | 052d3fc0907be253cfd64b2c737a0b0aca586011 (diff) | |
download | cpython-88ec9190105c9b03f49aaef601ce02b242a75273.zip cpython-88ec9190105c9b03f49aaef601ce02b242a75273.tar.gz cpython-88ec9190105c9b03f49aaef601ce02b242a75273.tar.bz2 |
bpo-40521: Make list free list per-interpreter (GH-20642)
Each interpreter now has its own list free list:
* Move list numfree and free_list into PyInterpreterState.
* Add _Py_list_state structure.
* Add tstate parameter to _PyList_ClearFreeList()
and _PyList_Fini().
* Remove "#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS".
* _PyGC_Fini() clears gcstate->garbage list which can be stored in
the list free list. Call _PyGC_Fini() before _PyList_Fini() to
prevent leaking this list.
Diffstat (limited to 'Objects/listobject.c')
-rw-r--r-- | Objects/listobject.c | 60 |
1 files changed, 29 insertions, 31 deletions
diff --git a/Objects/listobject.c b/Objects/listobject.c index 30d2620..043256d 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -96,65 +96,59 @@ list_preallocate_exact(PyListObject *self, Py_ssize_t size) return 0; } -/* Empty list reuse scheme to save calls to malloc and free */ -#ifndef PyList_MAXFREELIST -# define PyList_MAXFREELIST 80 -#endif - -/* bpo-40521: list free lists are shared by all interpreters. */ -#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS -# undef PyList_MAXFREELIST -# define PyList_MAXFREELIST 0 -#endif - -static PyListObject *free_list[PyList_MAXFREELIST]; -static int numfree = 0; - void -_PyList_ClearFreeList(void) +_PyList_ClearFreeList(PyThreadState *tstate) { - while (numfree) { - PyListObject *op = free_list[--numfree]; + struct _Py_list_state *state = &tstate->interp->list; + while (state->numfree) { + PyListObject *op = state->free_list[--state->numfree]; assert(PyList_CheckExact(op)); PyObject_GC_Del(op); } } void -_PyList_Fini(void) +_PyList_Fini(PyThreadState *tstate) { - _PyList_ClearFreeList(); + _PyList_ClearFreeList(tstate); } /* Print summary info about the state of the optimized allocator */ void _PyList_DebugMallocStats(FILE *out) { + PyInterpreterState *interp = _PyInterpreterState_GET(); + struct _Py_list_state *state = &interp->list; _PyDebugAllocatorStats(out, "free PyListObject", - numfree, sizeof(PyListObject)); + state->numfree, sizeof(PyListObject)); } PyObject * PyList_New(Py_ssize_t size) { - PyListObject *op; - if (size < 0) { PyErr_BadInternalCall(); return NULL; } - if (numfree) { - numfree--; - op = free_list[numfree]; + + PyInterpreterState *interp = _PyInterpreterState_GET(); + struct _Py_list_state *state = &interp->list; + PyListObject *op; + if (state->numfree) { + state->numfree--; + op = state->free_list[state->numfree]; _Py_NewReference((PyObject *)op); - } else { + } + else { op = PyObject_GC_New(PyListObject, &PyList_Type); - if (op == NULL) + if (op == NULL) { return NULL; + } } - if (size <= 0) + if (size <= 0) { op->ob_item = NULL; + } else { op->ob_item = (PyObject **) PyMem_Calloc(size, sizeof(PyObject *)); if (op->ob_item == NULL) { @@ -334,10 +328,14 @@ list_dealloc(PyListObject *op) } PyMem_FREE(op->ob_item); } - if (numfree < PyList_MAXFREELIST && PyList_CheckExact(op)) - free_list[numfree++] = op; - else + PyInterpreterState *interp = _PyInterpreterState_GET(); + struct _Py_list_state *state = &interp->list; + if (state->numfree < PyList_MAXFREELIST && PyList_CheckExact(op)) { + state->free_list[state->numfree++] = op; + } + else { Py_TYPE(op)->tp_free((PyObject *)op); + } Py_TRASHCAN_END } |