Skip to content

Commit 442628f

Browse files
generatedunixname1734921407115435meta-codesync[bot]
authored andcommitted
Sync pre-release CPython 3.15 branch from GitHub (2026-05-31)
Summary: Imported python/cpython `3.15.0b1+` from upstream rev [`9a39343`](https://www.github.com/python/cpython/commit/9a393438a7e30f4909c288a90f7637f4ce68e21a) (committed 2026-05-31 04:22:11+00:00). # Commit Info - Base: (`3.15.0b1+`) - [`2f91315`](https://www.github.com/python/cpython/commit/2f9131575b611dfc749242e8bbc6805bbc14683b) (commit date: 2026-05-29 21:48:10+00:00) - Imported: (`3.15.0b1+`) - [`9a39343`](https://www.github.com/python/cpython/commit/9a393438a7e30f4909c288a90f7637f4ce68e21a) (commit date: 2026-05-31 04:22:11+00:00) # Noteworthy file changes - Low-signal files (1 added) (NEWS.d, docs, .github) Complete list of added/removed files: https://www.internalfb.com/intern/everpaste/?color=0&handle=GAKHUCNn0F9DXbAGAKlYOuSQtZMpbr0LAAAz Differential Revision: D106969527 fbshipit-source-id: 20bafe4b6cea8e52a349efa4b8446fa4771356d9
1 parent 6919a37 commit 442628f

7 files changed

Lines changed: 177 additions & 33 deletions

File tree

Doc/howto/free-threading-python.rst

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,3 +165,132 @@ to false. If the flag is true then the :class:`warnings.catch_warnings`
165165
context manager uses a context variable for warning filters. If the flag is
166166
false then :class:`~warnings.catch_warnings` modifies the global filters list,
167167
which is not thread-safe. See the :mod:`warnings` module for more details.
168+
169+
170+
Increased memory usage
171+
----------------------
172+
173+
The free-threaded build will typically use more memory compared to the default
174+
build. There are multiple reasons for this, mostly due to design decisions.
175+
176+
177+
All interned strings are immortal
178+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
179+
180+
For modern Python versions (since version 2.3), interning a string (e.g. with
181+
:func:`sys.intern`) does not cause it to become immortal. Instead, if the last
182+
reference to that string disappears, it will be removed from the interned
183+
string table. This is not the case for the free-threaded build and any interned
184+
string will become immortal, surviving until interpreter shutdown.
185+
186+
187+
Non-GC objects have a larger object header
188+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
189+
190+
The free-threaded build uses a different :c:type:`PyObject` structure. Instead
191+
of having the GC related information allocated before the :c:type:`PyObject`
192+
structure, like in the default build, the GC related info is part of the normal
193+
object header. For example, on the AMD64 platform, ``None`` uses 32 bytes on
194+
the free-threaded build vs 16 bytes for the default build. GC objects (such as
195+
dicts and lists) are the same size for both builds since the free-threaded
196+
build does not use additional space for the GC info.
197+
198+
199+
QSBR can delay freeing of memory
200+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
201+
202+
In order to safely implement lock-free data structures, a safe memory
203+
reclamation (SMR) scheme is used, known as quiescent state-based reclamation
204+
(QSBR). This means that the memory backing data structures allowing lock-free
205+
access will use QSBR, which defers the free operation, rather than immediately
206+
freeing the memory. Two examples of these data structures are the list object
207+
and the dictionary keys object. See ``InternalDocs/qsbr.md`` in the CPython
208+
source tree for more details on how QSBR is implemented. Running
209+
:func:`gc.collect` should cause all memory being held by QSBR to be actually
210+
freed. Note that even when QSBR frees the memory, the underlying memory
211+
allocator may not immediately return that memory to the OS and so the resident
212+
set size (RSS) of the process might not decrease.
213+
214+
215+
mimalloc allocator vs pymalloc
216+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
217+
218+
The default build will normally use the "pymalloc" memory allocator for small
219+
allocations (512 bytes or smaller). The free-threaded build does not use
220+
pymalloc and allocates all Python objects using the "mimalloc" allocator. The
221+
pymalloc allocator has the following properties that help keep memory usage
222+
low: small per-allocated-block overhead, effective memory fragmentation
223+
prevention, and quick return of free memory to the operating system. The
224+
mimalloc allocator does quite well in these respects as well but can have some
225+
more overhead.
226+
227+
In the free-threaded build, mimalloc manages memory in a number of separate
228+
heaps (currently four). For example, all GC supporting objects are allocated
229+
from their own heap. Using separate heaps means that free memory in one heap
230+
cannot be used for an allocation that uses another heap. Also, some heaps are
231+
configured to use QSBR (quiescent-state based reclamation) when freeing the
232+
memory that backs up the heap (known as "pages" in mimalloc terminology). The
233+
use of QSBR creates a delay between all memory blocks for a page being freed
234+
and the memory page being released, either for new allocations or back to the
235+
OS.
236+
237+
The mimalloc allocator also defers returning freed memory back to the OS. You
238+
can reduce that delay by setting the environment variable
239+
:envvar:`!MIMALLOC_PURGE_DELAY` to ``0``. Note that this will likely reduce
240+
the performance of the allocator.
241+
242+
243+
Free-threaded reference counting can cause objects to live longer
244+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
245+
246+
In the default build, when an object's reference count reaches zero, it is
247+
normally deallocated. The free-threaded build uses "biased reference
248+
counting", with a fast-path for objects "owned" by the current thread and a
249+
slow path for other objects. See :pep:`703` for additional details. Any time
250+
an object's reference count ends up in a "queued" state, deallocation can be
251+
deferred. The queued state is cleared from the "eval breaker" section of the
252+
bytecode evaluator.
253+
254+
The free-threaded build also allows a different mode of reference counting,
255+
known as "deferred reference counting". This mode is enabled by setting a flag
256+
on a per-object basis. Deferred reference counting is enabled for the
257+
following types:
258+
259+
* module objects
260+
* module top-level functions
261+
* class methods defined in the class scope
262+
* descriptor objects
263+
* thread-local objects, created by :class:`threading.local`
264+
265+
When deferred reference counting is enabled, references from Python function
266+
stacks are not added to the reference count. This scheme reduces the overhead
267+
of reference counting, especially for objects used from multiple threads.
268+
Because the stack references are not counted, objects with deferred reference
269+
counting are not immediately freed when their internal reference count goes to
270+
zero. Instead, they are examined by the next GC run and, if no stack
271+
references to them are found, they are freed. This means these objects are
272+
freed by the GC and not when their reference count goes to zero, as is typical.
273+
274+
275+
Per-thread reference counting can delay freeing objects
276+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
277+
278+
To avoid contention on the reference count fields of frequently shared
279+
objects, the free-threaded build also uses "per-thread reference counting"
280+
for a few selected object types. Rather than updating a single shared
281+
reference count, each thread maintains its own local reference count array,
282+
indexed by a unique id assigned to the object. The true reference count is
283+
only computed by summing the per-thread counts when the object's local
284+
count drops to zero. Per-thread reference counting is currently used for:
285+
286+
* heap type objects (classes created in Python)
287+
* code objects
288+
* the ``__dict__`` of module objects
289+
290+
Because the per-thread counts must be merged back to the object before it
291+
can be deallocated, objects using per-thread reference counting are
292+
typically freed later than they would be in the default build. In
293+
particular, such an object is usually not freed until the thread that
294+
referenced it reaches a safe point (for example, in the "eval breaker"
295+
section of the bytecode evaluator) or exits. Running :func:`gc.collect`
296+
will merge the per-thread counts and allow these objects to be freed.

Doc/library/inspect.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1614,10 +1614,11 @@ properties, will be invoked and :meth:`~object.__getattr__` and
16141614
may be called.
16151615

16161616
For cases where you want passive introspection, like documentation tools, this
1617-
can be inconvenient. :func:`getattr_static` has the same signature as :func:`getattr`
1617+
can be inconvenient. :func:`getattr_static` has a similar signature as :func:`getattr`
16181618
but avoids executing code when it fetches attributes.
16191619

1620-
.. function:: getattr_static(obj, attr, default=None)
1620+
.. function:: getattr_static(obj, attr)
1621+
getattr_static(obj, attr, default)
16211622

16221623
Retrieve attributes without triggering dynamic lookup via the
16231624
descriptor protocol, :meth:`~object.__getattr__`

Doc/library/multiprocessing.rst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,10 @@ To show the individual process IDs involved, here is an expanded example::
100100
For an explanation of why the ``if __name__ == '__main__'`` part is
101101
necessary, see :ref:`multiprocessing-programming`.
102102

103-
The arguments to :class:`Process` usually need to be unpickleable from within
104-
the child process. If you tried typing the above example directly into a REPL it
105-
could lead to an :exc:`AttributeError` in the child process trying to locate the
106-
*f* function in the ``__main__`` module.
103+
The arguments to :class:`Process` usually need to be picklable so they can be
104+
passed to the child process. If you tried typing the above example directly
105+
into a REPL it could lead to an :exc:`AttributeError` in the child process
106+
trying to locate the *f* function in the ``__main__`` module.
107107

108108

109109
.. _multiprocessing-start-methods:

Doc/library/urllib.request.rst

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,7 +1051,7 @@ AbstractBasicAuthHandler Objects
10511051
*headers* should be the error headers.
10521052

10531053
*host* is either an authority (e.g. ``"python.org"``) or a URL containing an
1054-
authority component (e.g. ``"http://python.org/"``). In either case, the
1054+
authority component (e.g. ``"https://python.org/"``). In either case, the
10551055
authority must not contain a userinfo component (so, ``"python.org"`` and
10561056
``"python.org:80"`` are fine, ``"joe:password@python.org"`` is not).
10571057

@@ -1247,10 +1247,14 @@ This example gets the python.org main page and displays the first 300 bytes of
12471247
it::
12481248

12491249
>>> import urllib.request
1250-
>>> with urllib.request.urlopen('http://www.python.org/') as f:
1251-
... print(f.read(300))
1252-
...
1253-
b'<!doctype html>\n<!--[if lt IE 7]> <html class="no-js ie6 lt-ie7 lt-ie8 lt-ie9"> <![endif]-->\n<!--[if IE 7]> <html class="no-js ie7 lt-ie8 lt-ie9"> <![endif]-->\n<!--[if IE 8]> <html class="no-js ie8 lt-ie9">
1250+
>>> with urllib.request.urlopen('https://www.python.org/') as f:
1251+
... # The response may be compressed (for example, 'gzip').
1252+
... print(f.headers.get('Content-Encoding'))
1253+
... data = f.read()
1254+
... if f.headers.get('Content-Encoding') == 'gzip':
1255+
... import gzip
1256+
... data = gzip.decompress(data)
1257+
... print(data[:300].decode('utf-8', errors='replace'))
12541258

12551259
Note that urlopen returns a bytes object. This is because there is no way
12561260
for urlopen to automatically determine the encoding of the byte stream
@@ -1267,26 +1271,30 @@ For additional information, see the W3C document: https://www.w3.org/Internation
12671271
As the python.org website uses *utf-8* encoding as specified in its meta tag, we
12681272
will use the same for decoding the bytes object::
12691273

1270-
>>> with urllib.request.urlopen('http://www.python.org/') as f:
1271-
... print(f.read(100).decode('utf-8'))
1274+
>>> with urllib.request.urlopen('https://www.python.org/') as f:
1275+
... # Check for compression and decode appropriately.
1276+
... enc = f.headers.get('Content-Encoding')
1277+
... data = f.read()
1278+
... if enc == 'gzip':
1279+
... import gzip
1280+
... data = gzip.decompress(data)
1281+
... print(data[:100].decode('utf-8', errors='replace'))
12721282
...
1273-
<!doctype html>
1274-
<!--[if lt IE 7]> <html class="no-js ie6 lt-ie7 lt-ie8 lt-ie9"> <![endif]-->
1275-
<!-
12761283

12771284
It is also possible to achieve the same result without using the
12781285
:term:`context manager` approach::
12791286

12801287
>>> import urllib.request
1281-
>>> f = urllib.request.urlopen('http://www.python.org/')
1288+
>>> f = urllib.request.urlopen('https://www.python.org/')
12821289
>>> try:
1283-
... print(f.read(100).decode('utf-8'))
1290+
... enc = f.headers.get('Content-Encoding')
1291+
... data = f.read()
1292+
... if enc == 'gzip':
1293+
... import gzip
1294+
... data = gzip.decompress(data)
1295+
... print(data[:100].decode('utf-8', errors='replace'))
12841296
... finally:
12851297
... f.close()
1286-
...
1287-
<!doctype html>
1288-
<!--[if lt IE 7]> <html class="no-js ie6 lt-ie7 lt-ie8 lt-ie9"> <![endif]-->
1289-
<!--
12901298

12911299
In the following example, we are sending a data-stream to the stdin of a CGI
12921300
and reading the data it returns to us. Note that this example will only work
@@ -1357,7 +1365,7 @@ Use the *headers* argument to the :class:`Request` constructor, or::
13571365

13581366
import urllib.request
13591367
req = urllib.request.Request('http://www.example.com/')
1360-
req.add_header('Referer', 'http://www.python.org/')
1368+
req.add_header('Referer', 'https://www.python.org/')
13611369
# Customize the default User-Agent header value:
13621370
req.add_header('User-Agent', 'urllib-example/0.1 (Contact: . . .)')
13631371
with urllib.request.urlopen(req) as f:
@@ -1386,7 +1394,7 @@ containing parameters::
13861394
>>> import urllib.request
13871395
>>> import urllib.parse
13881396
>>> params = urllib.parse.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0})
1389-
>>> url = "http://www.musi-cal.com/cgi-bin/query?%s" % params
1397+
>>> url = "https://www.python.org/?%s" % params
13901398
>>> with urllib.request.urlopen(url) as f:
13911399
... print(f.read().decode('utf-8'))
13921400
...
@@ -1398,7 +1406,7 @@ from urlencode is encoded to bytes before it is sent to urlopen as data::
13981406
>>> import urllib.parse
13991407
>>> data = urllib.parse.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0})
14001408
>>> data = data.encode('ascii')
1401-
>>> with urllib.request.urlopen("http://requestb.in/xrbl82xr", data) as f:
1409+
>>> with urllib.request.urlopen("https://httpbin.org/post", data) as f:
14021410
... print(f.read().decode('utf-8'))
14031411
...
14041412

@@ -1408,15 +1416,15 @@ environment settings::
14081416
>>> import urllib.request
14091417
>>> proxies = {'http': 'http://proxy.example.com:8080/'}
14101418
>>> opener = urllib.request.build_opener(urllib.request.ProxyHandler(proxies))
1411-
>>> with opener.open("http://www.python.org") as f:
1419+
>>> with opener.open("https://www.python.org") as f:
14121420
... f.read().decode('utf-8')
14131421
...
14141422

14151423
The following example uses no proxies at all, overriding environment settings::
14161424

14171425
>>> import urllib.request
1418-
>>> opener = urllib.request.build_opener(urllib.request.ProxyHandler({}}))
1419-
>>> with opener.open("http://www.python.org/") as f:
1426+
>>> opener = urllib.request.build_opener(urllib.request.ProxyHandler({}))
1427+
>>> with opener.open("https://www.python.org/") as f:
14201428
... f.read().decode('utf-8')
14211429
...
14221430

@@ -1449,7 +1457,7 @@ some point in the future.
14491457
The following example illustrates the most common usage scenario::
14501458

14511459
>>> import urllib.request
1452-
>>> local_filename, headers = urllib.request.urlretrieve('http://python.org/')
1460+
>>> local_filename, headers = urllib.request.urlretrieve('https://python.org/')
14531461
>>> html = open(local_filename)
14541462
>>> html.close()
14551463

Doc/using/cmdline.rst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ additional methods of invocation:
5050
* When called with ``-c command``, it executes the Python statement(s) given as
5151
*command*. Here *command* may contain multiple statements separated by
5252
newlines.
53-
* When called with ``-m module-name``, the given module is located on the
54-
Python module path and executed as a script.
53+
* When called with ``-m module-name``, the given module is located using the standard
54+
import mechanism and executed as a script.
5555

5656
In non-interactive mode, the entire input is parsed before it is executed.
5757

@@ -78,8 +78,8 @@ source.
7878

7979
.. option:: -m <module-name>
8080

81-
Search :data:`sys.path` for the named module and execute its contents as
82-
the :mod:`__main__` module.
81+
Locate the module using the standard import mechanism and execute its contents
82+
as the :mod:`__main__` module.
8383

8484
Since the argument is a *module* name, you must not give a file extension
8585
(``.py``). The module name should be a valid absolute Python module name, but
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix a possible crash occurring during :mod:`socket` module initialization
2+
when the system is out of memory on platforms without a reentrant
3+
``gethostbyname``.

Modules/socketmodule.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9285,6 +9285,9 @@ socket_exec(PyObject *m)
92859285
/* Initialize gethostbyname lock */
92869286
#if defined(USE_GETHOSTBYNAME_LOCK)
92879287
netdb_lock = PyThread_allocate_lock();
9288+
if (netdb_lock == NULL) {
9289+
goto error;
9290+
}
92889291
#endif
92899292

92909293
#ifdef MS_WINDOWS

0 commit comments

Comments
 (0)