From 014ce8c46c044dc86bfb4443845cef4b894f8060 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 6 Sep 2023 12:16:39 -0600 Subject: [PATCH 1/9] Fix formatting. --- Doc/c-api/memory.rst | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst index 1df8c2b911ca8f..1d86806064bb17 100644 --- a/Doc/c-api/memory.rst +++ b/Doc/c-api/memory.rst @@ -112,16 +112,18 @@ by :c:func:`PyObject_Malloc` for allocating memory for buffers. The three allocation domains are: * Raw domain: intended for allocating memory for general-purpose memory - buffers where the allocation *must* go to the system allocator or where the - allocator can operate without the :term:`GIL`. The memory is requested directly - to the system. + buffers where the allocation *must* go to the system allocator or + where the allocator can operate without the :term:`GIL`. + The memory is requested directly from the system. * "Mem" domain: intended for allocating memory for Python buffers and - general-purpose memory buffers where the allocation must be performed with - the :term:`GIL` held. The memory is taken from the Python private heap. + general-purpose memory buffers where the allocation must be performed + with the :term:`GIL` held. + The memory is taken from the Python private heap. -* Object domain: intended for allocating memory belonging to Python objects. The - memory is taken from the Python private heap. +* Object domain: intended for allocating memory belonging + to Python objects. + The memory is taken from the Python private heap. When freeing memory previously allocated by the allocating functions belonging to a given domain,the matching specific deallocating functions must be used. For example, From 7a939e23652d1907c98660cb34d54555a79d289a Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 6 Sep 2023 12:51:00 -0600 Subject: [PATCH 2/9] Expand the definition of each allocator domain. --- Doc/c-api/memory.rst | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst index 1d86806064bb17..0afa4dead7ba7d 100644 --- a/Doc/c-api/memory.rst +++ b/Doc/c-api/memory.rst @@ -111,18 +111,24 @@ by :c:func:`PyObject_Malloc` for allocating memory for buffers. The three allocation domains are: -* Raw domain: intended for allocating memory for general-purpose memory - buffers where the allocation *must* go to the system allocator or - where the allocator can operate without the :term:`GIL`. +* Raw domain: intended for allocating memory independently + of the Python runtime. This includes cases where the + allocation *must* go to the system allocator, when the runtime might + not be initialized yet, or in non-Python threads. + It also includes where the allocator can operate without the :term:`GIL`. + Examples include general-purpose memory buffers, as well as global + state for applications that embed Python. The memory is requested directly from the system. -* "Mem" domain: intended for allocating memory for Python buffers and - general-purpose memory buffers where the allocation must be performed - with the :term:`GIL` held. +* "Mem" domain: intended for allocating memory tied to the + current interpreter but *not* belonging to any Python objects. + Examples include Python buffers, *arrays* of objects, + general-purpose memory buffers associated with an extension module, + and where the allocation must be performed with the :term:`GIL` held. The memory is taken from the Python private heap. -* Object domain: intended for allocating memory belonging - to Python objects. +* Object domain: intended for allocating memory belonging to Python + objects (which are necessarily tied to the current interpreter). The memory is taken from the Python private heap. When freeing memory previously allocated by the allocating functions belonging to a From 75def292cd9b6c68d50ee2d3ddf69e04027cee2c Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 6 Sep 2023 13:10:22 -0600 Subject: [PATCH 3/9] Clarify about the GIL. --- Doc/c-api/memory.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst index 0afa4dead7ba7d..dd139e5d5d234d 100644 --- a/Doc/c-api/memory.rst +++ b/Doc/c-api/memory.rst @@ -115,20 +115,21 @@ The three allocation domains are: of the Python runtime. This includes cases where the allocation *must* go to the system allocator, when the runtime might not be initialized yet, or in non-Python threads. - It also includes where the allocator can operate without the :term:`GIL`. Examples include general-purpose memory buffers, as well as global state for applications that embed Python. + The allocator may be called with or without the :term:`GIL` held. The memory is requested directly from the system. * "Mem" domain: intended for allocating memory tied to the current interpreter but *not* belonging to any Python objects. - Examples include Python buffers, *arrays* of objects, - general-purpose memory buffers associated with an extension module, - and where the allocation must be performed with the :term:`GIL` held. + Examples include Python buffers, *arrays* of objects, and + general-purpose memory buffers associated with an extension module. + The allocator will always be called with the :term:`GIL` held. The memory is taken from the Python private heap. * Object domain: intended for allocating memory belonging to Python objects (which are necessarily tied to the current interpreter). + The allocator will always be called with the :term:`GIL` held. The memory is taken from the Python private heap. When freeing memory previously allocated by the allocating functions belonging to a From 1f1a7595ca5824944a7600e148efde5ecc31e63b Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 6 Sep 2023 13:56:54 -0600 Subject: [PATCH 4/9] Add references to the interface/custom sections. --- Doc/c-api/memory.rst | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst index dd139e5d5d234d..b092d4045b61f0 100644 --- a/Doc/c-api/memory.rst +++ b/Doc/c-api/memory.rst @@ -119,6 +119,8 @@ The three allocation domains are: state for applications that embed Python. The allocator may be called with or without the :term:`GIL` held. The memory is requested directly from the system. + (Also see: :ref:`user API `, + :ref:`custom allocator `.) * "Mem" domain: intended for allocating memory tied to the current interpreter but *not* belonging to any Python objects. @@ -126,16 +128,23 @@ The three allocation domains are: general-purpose memory buffers associated with an extension module. The allocator will always be called with the :term:`GIL` held. The memory is taken from the Python private heap. + (Also see: :ref:`user API `, + :ref:`custom allocator `.) * Object domain: intended for allocating memory belonging to Python objects (which are necessarily tied to the current interpreter). The allocator will always be called with the :term:`GIL` held. The memory is taken from the Python private heap. + (Also see: :ref:`user API `, + :ref:`custom allocator `.) When freeing memory previously allocated by the allocating functions belonging to a given domain,the matching specific deallocating functions must be used. For example, :c:func:`PyMem_Free` must be used to free memory allocated using :c:func:`PyMem_Malloc`. + +.. _raw-interface: + Raw Memory Interface ==================== @@ -200,7 +209,7 @@ zero bytes. If *p* is ``NULL``, no operation is performed. -.. _memoryinterface: +.. _mem-interface: Memory Interface ================ @@ -308,6 +317,8 @@ versions and is therefore deprecated in extension modules. * ``PyMem_DEL(ptr)`` +.. _object-interface: + Object allocators ================= @@ -404,6 +415,13 @@ Legend: `. * "Debug build": :ref:`Python build in debug mode `. + +.. _custom-raw-allocator: + +.. _custom-mem-allocator: + +.. _custom-object-allocator: + .. _customize-memory-allocators: Customize Memory Allocators From 6320c803bb146b1cb8865108f50df075301b627a Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 6 Sep 2023 14:03:28 -0600 Subject: [PATCH 5/9] Clarify about using the same custom allocator to free memory. --- Doc/c-api/memory.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst index b092d4045b61f0..c49c6a49d62a2e 100644 --- a/Doc/c-api/memory.rst +++ b/Doc/c-api/memory.rst @@ -142,6 +142,11 @@ When freeing memory previously allocated by the allocating functions belonging t given domain,the matching specific deallocating functions must be used. For example, :c:func:`PyMem_Free` must be used to free memory allocated using :c:func:`PyMem_Malloc`. +Likewise, if one or more +:ref:`custom allocator ` is used +then any allocated memory must be freed using the same allocator +that provided it. + .. _raw-interface: From e4a4c9080503c2d5b69abf1254f30ff89fef6440 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 6 Sep 2023 14:05:16 -0600 Subject: [PATCH 6/9] Be explicit about which allocator domain is used. --- Doc/c-api/memory.rst | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst index c49c6a49d62a2e..74b4001bbb8ed5 100644 --- a/Doc/c-api/memory.rst +++ b/Doc/c-api/memory.rst @@ -157,7 +157,8 @@ The following function sets are wrappers to the system allocator. These functions are thread-safe, the :term:`GIL ` does not need to be held. -The :ref:`default raw memory allocator ` uses +These functions use the :ref:`raw ` allocator. +:ref:`By default `, the allocator uses the following functions: :c:func:`malloc`, :c:func:`calloc`, :c:func:`realloc` and :c:func:`!free`; call ``malloc(1)`` (or ``calloc(1, 1)``) when requesting zero bytes. @@ -223,8 +224,9 @@ The following function sets, modeled after the ANSI C standard, but specifying behavior when requesting zero bytes, are available for allocating and releasing memory from the Python heap. -The :ref:`default memory allocator ` uses the -:ref:`pymalloc memory allocator `. +These functions use the :ref:`"mem" ` allocator. +:ref:`By default ` the "mem" allocator uses +the :ref:`pymalloc memory allocator `. .. warning:: @@ -337,8 +339,9 @@ memory from the Python heap. functions in this domain by the methods described in the :ref:`Customize Memory Allocators ` section. -The :ref:`default object allocator ` uses the -:ref:`pymalloc memory allocator `. +These functions use the :ref:`"mem" ` allocator. +:ref:`By default ` the object allocator uses +the :ref:`pymalloc memory allocator `. .. warning:: From 2e155a05b7522d089c69419d9d6d25c09848e9df Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 6 Sep 2023 14:10:04 -0600 Subject: [PATCH 7/9] Clarify about using the same interpreter to free. --- Doc/c-api/memory.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst index 74b4001bbb8ed5..02d30ab8dd6dc2 100644 --- a/Doc/c-api/memory.rst +++ b/Doc/c-api/memory.rst @@ -157,6 +157,11 @@ The following function sets are wrappers to the system allocator. These functions are thread-safe, the :term:`GIL ` does not need to be held. +Use of these functions is not restricted by the current state of the +Python runtime. Likewise, they are not constrained by which interpreter +is active in the current thread or even if there is one. The allocated +memory is process-global and independent of the Python runtime. + These functions use the :ref:`raw ` allocator. :ref:`By default `, the allocator uses the following functions: :c:func:`malloc`, :c:func:`calloc`, :c:func:`realloc` @@ -224,6 +229,10 @@ The following function sets, modeled after the ANSI C standard, but specifying behavior when requesting zero bytes, are available for allocating and releasing memory from the Python heap. +All allocations happen relative to the current interpreter. Subsequent +free (and realloc) operations on the allocated memory must be made using +the same interpreter. + These functions use the :ref:`"mem" ` allocator. :ref:`By default ` the "mem" allocator uses the :ref:`pymalloc memory allocator `. @@ -339,6 +348,10 @@ memory from the Python heap. functions in this domain by the methods described in the :ref:`Customize Memory Allocators ` section. +All allocations happen relative to the current interpreter. Subsequent +free (and realloc) operations on the allocated memory must be made using +the same interpreter. + These functions use the :ref:`"mem" ` allocator. :ref:`By default ` the object allocator uses the :ref:`pymalloc memory allocator `. From 44074dbf30801acaa90895e1815010e2cb8fba0c Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 6 Sep 2023 15:54:09 -0600 Subject: [PATCH 8/9] Add an explanation to the custom allocators section. --- Doc/c-api/memory.rst | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst index 02d30ab8dd6dc2..c8b8b627c8a6e0 100644 --- a/Doc/c-api/memory.rst +++ b/Doc/c-api/memory.rst @@ -448,6 +448,35 @@ Legend: Customize Memory Allocators =========================== +The Python runtime may be configured, with :c:func:`PyMem_SetAllocator`, +to use custom allocators for any of the +:ref:`supported allocator domains `. +There are two kinds of custom allocator: + +* actual allocator implementations +* wrappers around other allocators (AKA "hooks") + +Applications that embed Python may set either kind before the runtime +is initialized (e.g. with :c:func:`Py_InitializeFromConfig`). However, +from that point on only wrappers around the current allocator +(see :c:func:`PyMem_GetAllocator`) may be set. Thus, extension modules +may only set wrappers. + +An actual allocator is responsible for managing its own state and memory +pool. For the "mem" and "object" domains, the allocator is responsible +for maintaining its state and allocations relative to the +:c:func:`current interpreter `. +The ``PyMemAllocatorEx.ctx`` field may be ``NULL`` for +this kind of allocator. + +A wrapper can be useful for tracking allocations, adjusting the behavior +of another allocator (e.g. handling failures differently), or debugging. +For example, debug builds of CPython use a wrapper to track memory usage +and find memory leaks, and the :mod:`tracemalloc` module sets a wrapper +to identify where allocations happen. Typically, the wrapped allocator +is stored in (or within) the ``PyMemAllocatorEx.ctx`` field +of the wrapper. + .. versionadded:: 3.4 .. c:type:: PyMemAllocatorEx From fde578552a95336341c9c32afa42a8aaf0fa5473 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 6 Sep 2023 15:54:58 -0600 Subject: [PATCH 9/9] Enumerate characteristics for custom allocators. --- Doc/c-api/memory.rst | 50 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst index c8b8b627c8a6e0..7bd108c330efa3 100644 --- a/Doc/c-api/memory.rst +++ b/Doc/c-api/memory.rst @@ -437,12 +437,6 @@ Legend: * "Debug build": :ref:`Python build in debug mode `. -.. _custom-raw-allocator: - -.. _custom-mem-allocator: - -.. _custom-object-allocator: - .. _customize-memory-allocators: Customize Memory Allocators @@ -477,6 +471,50 @@ to identify where allocations happen. Typically, the wrapped allocator is stored in (or within) the ``PyMemAllocatorEx.ctx`` field of the wrapper. +Regardless of the kind, the following applies to every custom +allocator, depending on the domain: + +.. _custom-raw-allocator: + +Raw domain: + +* a system allocator (or wrapper around one) +* the memory is requested directly from the system +* independent of the Python runtime +* not associated with any interpreter +* may be used before the runtime is initialized and after it's finalized +* may be used with the runtime in an unknown state +* must be thread-safe +* must work whether or not the :term:`GIL` is held + +.. _custom-mem-allocator: + +"Mem" domain: + +* may use a Python-specific heap +* allocated memory will be used only in a single interpreter +* memory for each interpreter is likely kept separate +* must be thread-safe +* always called with the runtime in an active, stable state +* always called with the target interpreter/tstate set in the current thread + (:c:func:`PyInterpreterState_Get`, :c:func:`PyThreadState_Get`) +* always called with the current interpreter's :term:`GIL` held +* never used for memory belonging to Python objects + +.. _custom-object-allocator: + +Object domain: + +* will use a Python-specific heap +* allocated memory will be used only in a single interpreter +* memory for each interpreter is kept separate +* must be thread-safe +* always called with the runtime in an active, stable state +* always called with the target interpreter/tstate set in the current thread + (:c:func:`PyInterpreterState_Get`, :c:func:`PyThreadState_Get`) +* always called with the current interpreter's :term:`GIL` held +* only used for memory belonging to Python objects + .. versionadded:: 3.4 .. c:type:: PyMemAllocatorEx