https://github.com/python/cpython/commit/6fb51f23f7973560c009552c61e86955584a2fb2
commit: 6fb51f23f7973560c009552c61e86955584a2fb2
branch: main
author: John <[email protected]>
committer: ZeroIntensity <[email protected]>
date: 2026-07-22T18:43:18-04:00
summary:

gh-154401: Skip fetching the thread state for non-GC types in `_Py_Dealloc` 
(GH-154430)

_Py_Dealloc() fetched the current thread state and computed the C
recursion margin on every deallocation, but both are only used by the
trashcan mechanism, which applies only to GC-tracked types. Gate them
behind the Py_TPFLAGS_HAVE_GC check so the common non-GC case (int,
float, str and similar atomic types) skips them.

On platforms where _PyThreadState_GET() reads a _Thread_local via a
function call (e.g. macOS TLV), this removes a call from every non-GC
deallocation.

Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>

files:
A 
Misc/NEWS.d/next/Core_and_Builtins/2026-07-22-14-30-00.gh-issue-154429.Qk9mZ2.rst
M Objects/object.c

diff --git 
a/Misc/NEWS.d/next/Core_and_Builtins/2026-07-22-14-30-00.gh-issue-154429.Qk9mZ2.rst
 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-22-14-30-00.gh-issue-154429.Qk9mZ2.rst
new file mode 100644
index 00000000000000..04781b03356b9f
--- /dev/null
+++ 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-22-14-30-00.gh-issue-154429.Qk9mZ2.rst
@@ -0,0 +1,2 @@
+Slightly speed up deallocation of objects that are not tracked by the garbage
+collector, such as :class:`int`, :class:`float` and :class:`str`.
diff --git a/Objects/object.c b/Objects/object.c
index bd23c2e2388194..fadd9273a36607 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -3292,13 +3292,20 @@ _Py_Dealloc(PyObject *op)
     PyTypeObject *type = Py_TYPE(op);
     unsigned long gc_flag = type->tp_flags & Py_TPFLAGS_HAVE_GC;
     destructor dealloc = type->tp_dealloc;
-    PyThreadState *tstate = _PyThreadState_GET();
-    intptr_t margin = _Py_RecursionLimit_GetMargin(tstate);
-    if (margin < 2 && gc_flag) {
-        _PyTrash_thread_deposit_object(tstate, (PyObject *)op);
-        return;
+    PyThreadState *tstate = NULL;
+    intptr_t margin = 0;
+    if (gc_flag) {
+        tstate = _PyThreadState_GET();
+        margin = _Py_RecursionLimit_GetMargin(tstate);
+        if (margin < 2) {
+            _PyTrash_thread_deposit_object(tstate, (PyObject *)op);
+            return;
+        }
     }
 #ifdef Py_DEBUG
+    if (tstate == NULL) {
+        tstate = _PyThreadState_GET();
+    }
 #if !defined(Py_GIL_DISABLED) && !defined(Py_STACKREF_DEBUG)
     /* This assertion doesn't hold for the free-threading build, as
      * PyStackRef_CLOSE_SPECIALIZED is not implemented */
@@ -3340,7 +3347,7 @@ _Py_Dealloc(PyObject *op)
     Py_XDECREF(old_exc);
     Py_DECREF(type);
 #endif
-    if (tstate->delete_later && margin >= 4 && gc_flag) {
+    if (gc_flag && tstate->delete_later && margin >= 4) {
         _PyTrash_thread_destroy_chain(tstate);
     }
 }

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to