diff --git a/Include/methodobject.h b/Include/methodobject.h index ab66b03f7a9..9f5f7c482c8 100644 --- a/Include/methodobject.h +++ b/Include/methodobject.h @@ -99,11 +99,6 @@ typedef struct { PyAPI_FUNC(int) PyCFunction_ClearFreeList(void); -#ifndef Py_LIMITED_API -PyAPI_FUNC(void) _PyCFunction_DebugMallocStats(FILE *out); -PyAPI_FUNC(void) _PyMethod_DebugMallocStats(FILE *out); -#endif - #ifdef __cplusplus } #endif diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-07-25-11-06-57.bpo-37340.5ktLEg.rst b/Misc/NEWS.d/next/Core and Builtins/2019-07-25-11-06-57.bpo-37340.5ktLEg.rst new file mode 100644 index 00000000000..e61146b6f79 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2019-07-25-11-06-57.bpo-37340.5ktLEg.rst @@ -0,0 +1,3 @@ +Removed object cache (``free_list``) for bound method objects. Temporary +bound method objects are less used than before thanks to the ``LOAD_METHOD`` +opcode and the ``_PyObject_VectorcallMethod`` C API. diff --git a/Objects/classobject.c b/Objects/classobject.c index 46525a737bc..40cbeaa9f2a 100644 --- a/Objects/classobject.c +++ b/Objects/classobject.c @@ -8,15 +8,6 @@ #define TP_DESCR_GET(t) ((t)->tp_descr_get) -/* Free list for method objects to safe malloc/free overhead - * The im_self element is used to chain the elements. - */ -static PyMethodObject *free_list; -static int numfree = 0; -#ifndef PyMethod_MAXFREELIST -#define PyMethod_MAXFREELIST 256 -#endif - _Py_IDENTIFIER(__name__); _Py_IDENTIFIER(__qualname__); @@ -103,21 +94,13 @@ method_vectorcall(PyObject *method, PyObject *const *args, PyObject * PyMethod_New(PyObject *func, PyObject *self) { - PyMethodObject *im; if (self == NULL) { PyErr_BadInternalCall(); return NULL; } - im = free_list; - if (im != NULL) { - free_list = (PyMethodObject *)(im->im_self); - (void)PyObject_INIT(im, &PyMethod_Type); - numfree--; - } - else { - im = PyObject_GC_New(PyMethodObject, &PyMethod_Type); - if (im == NULL) - return NULL; + PyMethodObject *im = PyObject_GC_New(PyMethodObject, &PyMethod_Type); + if (im == NULL) { + return NULL; } im->im_weakreflist = NULL; Py_INCREF(func); @@ -252,14 +235,7 @@ method_dealloc(PyMethodObject *im) PyObject_ClearWeakRefs((PyObject *)im); Py_DECREF(im->im_func); Py_XDECREF(im->im_self); - if (numfree < PyMethod_MAXFREELIST) { - im->im_self = (PyObject *)free_list; - free_list = im; - numfree++; - } - else { - PyObject_GC_Del(im); - } + PyObject_GC_Del(im); } static PyObject * @@ -395,16 +371,7 @@ PyTypeObject PyMethod_Type = { int PyMethod_ClearFreeList(void) { - int freelist_size = numfree; - - while (free_list) { - PyMethodObject *im = free_list; - free_list = (PyMethodObject *)(im->im_self); - PyObject_GC_Del(im); - numfree--; - } - assert(numfree == 0); - return freelist_size; + return 0; } void @@ -413,15 +380,6 @@ PyMethod_Fini(void) (void)PyMethod_ClearFreeList(); } -/* Print summary info about the state of the optimized allocator */ -void -_PyMethod_DebugMallocStats(FILE *out) -{ - _PyDebugAllocatorStats(out, - "free PyMethodObject", - numfree, sizeof(PyMethodObject)); -} - /* ------------------------------------------------------------------------ * instance method */ diff --git a/Objects/methodobject.c b/Objects/methodobject.c index 3494f11d80f..b9977467ac0 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -7,15 +7,6 @@ #include "pycore_pystate.h" #include "structmember.h" -/* Free list for method objects to safe malloc/free overhead - * The m_self element is used to chain the objects. - */ -static PyCFunctionObject *free_list = NULL; -static int numfree = 0; -#ifndef PyCFunction_MAXFREELIST -#define PyCFunction_MAXFREELIST 256 -#endif - /* undefine macro trampoline to PyCFunction_NewEx */ #undef PyCFunction_New @@ -66,17 +57,10 @@ PyCFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module) return NULL; } - PyCFunctionObject *op; - op = free_list; - if (op != NULL) { - free_list = (PyCFunctionObject *)(op->m_self); - (void)PyObject_INIT(op, &PyCFunction_Type); - numfree--; - } - else { - op = PyObject_GC_New(PyCFunctionObject, &PyCFunction_Type); - if (op == NULL) - return NULL; + PyCFunctionObject *op = + PyObject_GC_New(PyCFunctionObject, &PyCFunction_Type); + if (op == NULL) { + return NULL; } op->m_weakreflist = NULL; op->m_ml = ml; @@ -130,14 +114,7 @@ meth_dealloc(PyCFunctionObject *m) } Py_XDECREF(m->m_self); Py_XDECREF(m->m_module); - if (numfree < PyCFunction_MAXFREELIST) { - m->m_self = (PyObject *)free_list; - free_list = m; - numfree++; - } - else { - PyObject_GC_Del(m); - } + PyObject_GC_Del(m); } static PyObject * @@ -338,16 +315,7 @@ PyTypeObject PyCFunction_Type = { int PyCFunction_ClearFreeList(void) { - int freelist_size = numfree; - - while (free_list) { - PyCFunctionObject *v = free_list; - free_list = (PyCFunctionObject *)(v->m_self); - PyObject_GC_Del(v); - numfree--; - } - assert(numfree == 0); - return freelist_size; + return 0; } void @@ -356,15 +324,6 @@ PyCFunction_Fini(void) (void)PyCFunction_ClearFreeList(); } -/* Print summary info about the state of the optimized allocator */ -void -_PyCFunction_DebugMallocStats(FILE *out) -{ - _PyDebugAllocatorStats(out, - "free PyCFunctionObject", - numfree, sizeof(PyCFunctionObject)); -} - /* Vectorcall functions for each of the PyCFunction calling conventions, * except for METH_VARARGS (possibly combined with METH_KEYWORDS) which diff --git a/Objects/object.c b/Objects/object.c index 585a9748c84..ee2050656a0 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -1959,12 +1959,10 @@ Py_ssize_t (*_Py_abstract_hack)(PyObject *) = PyObject_Size; void _PyObject_DebugTypeStats(FILE *out) { - _PyCFunction_DebugMallocStats(out); _PyDict_DebugMallocStats(out); _PyFloat_DebugMallocStats(out); _PyFrame_DebugMallocStats(out); _PyList_DebugMallocStats(out); - _PyMethod_DebugMallocStats(out); _PyTuple_DebugMallocStats(out); }