Skip to content

Why does Python 3.14 use ob_ref_local and ob_ref_shared for reference counts when GIL is absent #130173

@pypy66

Description

@pypy66

According to Include/object.h in Python's source code:

struct _object {
    // ob_tid stores the thread id (or zero). It is also used by the GC and the
    // trashcan mechanism as a linked list pointer and by the GC to store the
    // computed "gc_refs" refcount.
    uintptr_t ob_tid;
    uint16_t ob_flags;
    PyMutex ob_mutex;           // per-object lock
    uint8_t ob_gc_bits;         // gc-related state
    uint32_t ob_ref_local;      // local reference count
    Py_ssize_t ob_ref_shared;   // shared (atomic) reference count
    PyTypeObject *ob_type;
};

When I managed to use an external tool, pyobject (pip install pyobject), to inspect them:

C:\Users\admin>py314t
Python 3.14.0a5 experimental free-threading build (tags/v3.14.0a5:3ae9101, Feb 11 2025, 17:44:01) [MSC v.1942 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from pyobject import getrefcount_nogil,setrefcount_nogil
>>> class A:pass
...
>>> a=A()
>>> getrefcount_nogil(a)
(1, 0) # the first is ob_ref_local and the second is ob_ref_shared
>>> def another_thread():
...     b=a
...     while True:pass
...
>>> from _thread import start_new_thread
>>> start_new_thread(another_thread,())
10824
>>> getrefcount_nogil(a)
(1, 5)
>>>

Snippet of getrefcount_nogil from the source code of pyobject:

PyObject *getrefcount_nogil(PyObject *self, PyObject *args){
    PyObject *obj;
    if (!PyArg_ParseTuple(args,"O",&obj)) return NULL;
    PyObject *result = PyTuple_New(2); // Simply returns a tuple
    PyTuple_SetItem(result, 0, PyLong_FromUnsignedLong(obj->ob_ref_local));
    PyTuple_SetItem(result, 1, PyLong_FromSize_t(obj->ob_ref_shared));
    return result;
}

So, what is the function and implication of ob_ref_local and ob_ref_shared values that replace ob_refcnt?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions