bpo-40521: Make dict free lists per-interpreter (GH-20645)

Each interpreter now has its own dict free list:

* Move dict free lists into PyInterpreterState.
* Move PyDict_MAXFREELIST define to pycore_interp.h
* Add _Py_dict_state structure.
* Add tstate parameter to _PyDict_ClearFreeList() and _PyDict_Fini().
* In debug mode, ensure that the dict free lists are not used after
  _PyDict_Fini() is called.
* Remove "#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS".
This commit is contained in:
Victor Stinner 2020-06-23 11:33:18 +02:00 committed by GitHub
parent 26a1ad1c24
commit b4e85cadfb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 102 additions and 85 deletions

View file

@ -169,7 +169,7 @@ extern void _PyFrame_ClearFreeList(PyThreadState *tstate);
extern void _PyTuple_ClearFreeList(PyThreadState *tstate);
extern void _PyFloat_ClearFreeList(PyThreadState *tstate);
extern void _PyList_ClearFreeList(PyThreadState *tstate);
extern void _PyDict_ClearFreeList(void);
extern void _PyDict_ClearFreeList(PyThreadState *tstate);
extern void _PyAsyncGen_ClearFreeLists(PyThreadState *tstate);
extern void _PyContext_ClearFreeList(PyThreadState *tstate);

View file

@ -69,6 +69,14 @@ struct _Py_unicode_state {
struct _Py_unicode_fs_codec fs_codec;
};
struct _Py_float_state {
/* Special free list
free_list is a singly-linked list of available PyFloatObjects,
linked via abuse of their ob_type members. */
int numfree;
PyFloatObject *free_list;
};
/* Speed optimization to avoid frequent malloc/free of small tuples */
#ifndef PyTuple_MAXSAVESIZE
// Largest tuple to save on free list
@ -99,12 +107,16 @@ struct _Py_list_state {
int numfree;
};
struct _Py_float_state {
/* Special free list
free_list is a singly-linked list of available PyFloatObjects,
linked via abuse of their ob_type members. */
#ifndef PyDict_MAXFREELIST
# define PyDict_MAXFREELIST 80
#endif
struct _Py_dict_state {
/* Dictionary reuse scheme to save calls to malloc and free */
PyDictObject *free_list[PyDict_MAXFREELIST];
int numfree;
PyFloatObject *free_list;
PyDictKeysObject *keys_free_list[PyDict_MAXFREELIST];
int keys_numfree;
};
struct _Py_frame_state {
@ -136,7 +148,6 @@ struct _Py_context_state {
};
/* interpreter state */
#define _PY_NSMALLPOSINTS 257
@ -182,8 +193,6 @@ struct _is {
PyObject *codec_error_registry;
int codecs_initialized;
struct _Py_unicode_state unicode;
PyConfig config;
#ifdef HAVE_DLOPEN
int dlopenflags;
@ -224,16 +233,18 @@ struct _is {
*/
PyLongObject* small_ints[_PY_NSMALLNEGINTS + _PY_NSMALLPOSINTS];
#endif
struct _Py_tuple_state tuple;
struct _Py_list_state list;
struct _Py_unicode_state unicode;
struct _Py_float_state float_state;
struct _Py_frame_state frame;
struct _Py_async_gen_state async_gen;
struct _Py_context_state context;
/* Using a cache is very effective since typically only a single slice is
created and then deleted again. */
PySliceObject *slice_cache;
struct _Py_tuple_state tuple;
struct _Py_list_state list;
struct _Py_dict_state dict_state;
struct _Py_frame_state frame;
struct _Py_async_gen_state async_gen;
struct _Py_context_state context;
};
/* Used by _PyImport_Cleanup() */

View file

@ -59,7 +59,7 @@ extern PyStatus _PyGC_Init(PyThreadState *tstate);
/* Various internal finalizers */
extern void _PyFrame_Fini(PyThreadState *tstate);
extern void _PyDict_Fini(void);
extern void _PyDict_Fini(PyThreadState *tstate);
extern void _PyTuple_Fini(PyThreadState *tstate);
extern void _PyList_Fini(PyThreadState *tstate);
extern void _PySet_Fini(void);