Build1 publisher2 min readPublished
Mark Shannon's bid for 32 PyObject header bits waits on free-threaded abi3t
Mark Shannon pitched a one-time Stable ABI break at the 2026 Python Language Summit to reclaim 32 unused bits in the PyObject header. The reply folds it into the abi3t move C extension authors already face, on a schedule still to be set.
The Engineer · Build desk

What happened
- Shannon said the reclaimed bits would let him implement a better garbage collector and faster allocations.
- He said packages built on the Stable ABI will have to move to abi3t, the free-threading ABI, regardless of what happens to the header.
- Thomas Wouters proposed waiting until abi3t is the only Stable ABI, since free-threaded Python never promised compatibility for its object layout.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- cost Maintainers of abi3 extensions carry the porting, recompiling and multi-ABI support Shannon described either way; the sequencing decides whether they pay for it once or twice.
- constraint Garbage collector and allocation work that needs the high refcount bits stays blocked until free-threading is the default and abi3t is the only Stable ABI.
- decision Teams shipping C extensions can plan the abi3t port as their single header-related migration, but they cannot yet pin it to a release.
The header has two fields. `ob_refcnt` is a `Py_ssize_t`, `ob_type` is a pointer to the type, and Shannon wants the high bits of the first one [1]. Since PEP 683 was accepted in Python 3.12, the reference count has effectively been treated as a 32-bit integer [2]. That leaves 32 spare bits the core team still cannot use [3].
The blocker is the default build. Non-free-threaded Python exposed details about `ob_refcnt` in the Stable ABI [10]. So the bits stay closed to other uses, to prevent breakages [3]. With them, Shannon said, he could implement a better garbage collector and faster allocations [4].
Shannon did not pretend the break was free. It would be "easy to do... probably not painless though," he said [5]. The pain is users having to port, recompile and support multiple ABIs [6]. Then he pointed at the free-threading ABI. "Well... it's going to happen anyway," Mark said [7]. Packages that depend on the Stable ABI would have to move to abi3t [8].
Thomas Wouters answered with an ordering argument: wait until there is only one Stable ABI, abi3t [9]. Free-threaded Python has not promised Stable ABI compatibility for its object layout [10]. According to the summit write-up, once free-threading becomes the default, the Stable ABI that exposes header internals goes away, and the team can change the header more freely [11]. The write-up records that it dawned on Shannon, "to his horror," that free-threaded Python may be solving his problem [12].
I think Wouters has the order right. A standalone break now, followed by the abi3t move, would put every abi3 extension through two ports. Folding the header change into abi3t makes it one [1]. The price is paid in waiting. The GC and allocation work sits behind the free-threaded default.
That also limits how precisely extension teams can budget. The record is a lightning talk and one reply from the room [14]. The write-up does not give a release for the free-threaded default, or for the point where abi3t becomes the only Stable ABI. A team shipping abi3 wheels can plan on the abi3t port Shannon called inevitable [8], with the header change riding on it [9]. The write-up ends the session on "We'll just have to be patient!" [13]
What to watch
- A PEP or steering council decision naming the release where free-threading becomes the default build.
- A dated plan for when abi3t becomes the only Stable ABI and abi3 wheels stop loading.
- A concrete proposal from Shannon for the header bits, with measured GC or allocation gains attached.