diff --git a/Misc/NEWS.d/next/Library/2017-12-25-20-22-47.bpo-32422.5H3Wq2.rst b/Misc/NEWS.d/next/Library/2017-12-25-20-22-47.bpo-32422.5H3Wq2.rst new file mode 100644 index 00000000000..5918c322237 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2017-12-25-20-22-47.bpo-32422.5H3Wq2.rst @@ -0,0 +1,2 @@ +``functools.lru_cache`` uses less memory (3 words for each cached key) and +takes about 1/3 time for cyclic GC. diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c index a571045bcc7..ff4172d663b 100644 --- a/Modules/_functoolsmodule.c +++ b/Modules/_functoolsmodule.c @@ -677,26 +677,9 @@ typedef struct lru_list_elem { static void lru_list_elem_dealloc(lru_list_elem *link) { - _PyObject_GC_UNTRACK(link); Py_XDECREF(link->key); Py_XDECREF(link->result); - PyObject_GC_Del(link); -} - -static int -lru_list_elem_traverse(lru_list_elem *link, visitproc visit, void *arg) -{ - Py_VISIT(link->key); - Py_VISIT(link->result); - return 0; -} - -static int -lru_list_elem_clear(lru_list_elem *link) -{ - Py_CLEAR(link->key); - Py_CLEAR(link->result); - return 0; + PyObject_Del(link); } static PyTypeObject lru_list_elem_type = { @@ -720,10 +703,7 @@ static PyTypeObject lru_list_elem_type = { 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - 0, /* tp_doc */ - (traverseproc)lru_list_elem_traverse, /* tp_traverse */ - (inquiry)lru_list_elem_clear, /* tp_clear */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ }; @@ -959,8 +939,8 @@ bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds } } else { /* Put result in a new link at the front of the queue. */ - link = (lru_list_elem *)PyObject_GC_New(lru_list_elem, - &lru_list_elem_type); + link = (lru_list_elem *)PyObject_New(lru_list_elem, + &lru_list_elem_type); if (link == NULL) { Py_DECREF(key); Py_DECREF(result); @@ -970,7 +950,6 @@ bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds link->hash = hash; link->key = key; link->result = result; - _PyObject_GC_TRACK(link); if (_PyDict_SetItem_KnownHash(self->cache, key, (PyObject *)link, hash) < 0) { Py_DECREF(link); @@ -1151,7 +1130,8 @@ lru_cache_tp_traverse(lru_cache_object *self, visitproc visit, void *arg) lru_list_elem *link = self->root.next; while (link != &self->root) { lru_list_elem *next = link->next; - Py_VISIT(link); + Py_VISIT(link->key); + Py_VISIT(link->result); link = next; } Py_VISIT(self->maxsize_O);