PEP 445: cleanup
Avoid "should", "may" and "might". Rephrase some sentences
This commit is contained in:
parent
feef345e1e
commit
03210e6ffd
218
pep-0445.txt
218
pep-0445.txt
|
@ -12,7 +12,8 @@ Python-Version: 3.4
|
||||||
Abstract
|
Abstract
|
||||||
========
|
========
|
||||||
|
|
||||||
Add new APIs to customize Python memory allocators.
|
Add new Application Programming Interfaces (API) to customize Python
|
||||||
|
memory allocators.
|
||||||
|
|
||||||
|
|
||||||
Rationale
|
Rationale
|
||||||
|
@ -20,21 +21,22 @@ Rationale
|
||||||
|
|
||||||
Use cases:
|
Use cases:
|
||||||
|
|
||||||
* Application embedding Python may want to isolate Python memory from
|
* Applications embedding Python which want to isolate Python memory from
|
||||||
the memory of the application, or may want to use a different memory
|
the memory of the application, or want to use a different memory
|
||||||
allocator optimized for its Python usage
|
allocator optimized for its Python usage
|
||||||
* Python running on embedded devices with low memory and slow CPU.
|
* Python running on embedded devices with low memory and slow CPU.
|
||||||
A custom memory allocator may be required to use efficiently the
|
A custom memory allocator can be used for efficiency and/or to get
|
||||||
memory and/or to be able to use all the memory of the device.
|
access all the memory of the device.
|
||||||
* Debug tool to:
|
* Debug tools for memory allocators:
|
||||||
|
|
||||||
- track the memory usage (memory leaks)
|
- track the memory usage (find memory leaks)
|
||||||
- get the Python filename and line number where an object was
|
- get the location of a memory allocation: Python filename and line
|
||||||
allocated
|
number, and the size of a memory block
|
||||||
- detect buffer underflow, buffer overflow and detect misuse of Python
|
- detect buffer underflow, buffer overflow and misuse of Python
|
||||||
allocator APIs (builtin Python debug hooks)
|
allocator APIs (see `Redesign Debug Checks on Memory Block
|
||||||
- force allocation to fail to test handling of ``MemoryError``
|
Allocators as Hooks`_)
|
||||||
exception
|
- force memory allocations to fail to test handling of the
|
||||||
|
``MemoryError`` exception
|
||||||
|
|
||||||
|
|
||||||
Proposal
|
Proposal
|
||||||
|
@ -56,8 +58,7 @@ New Functions and Structures
|
||||||
* Add a new ``PyMemAllocator`` structure::
|
* Add a new ``PyMemAllocator`` structure::
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* user context passed as the first argument
|
/* user context passed as the first argument to the 3 functions */
|
||||||
to the 3 functions */
|
|
||||||
void *ctx;
|
void *ctx;
|
||||||
|
|
||||||
/* allocate a memory block */
|
/* allocate a memory block */
|
||||||
|
@ -82,7 +83,7 @@ New Functions and Structures
|
||||||
- ``PYMEM_DOMAIN_OBJ``: ``PyObject_Malloc()``, ``PyObject_Realloc()``
|
- ``PYMEM_DOMAIN_OBJ``: ``PyObject_Malloc()``, ``PyObject_Realloc()``
|
||||||
and ``PyObject_Free()``
|
and ``PyObject_Free()``
|
||||||
|
|
||||||
* Add new functions to get and set memory allocators:
|
* Add new functions to get and set memory block allocators:
|
||||||
|
|
||||||
- ``void PyMem_GetAllocator(PyMemAllocatorDomain domain, PyMemAllocator *allocator)``
|
- ``void PyMem_GetAllocator(PyMemAllocatorDomain domain, PyMemAllocator *allocator)``
|
||||||
- ``void PyMem_SetAllocator(PyMemAllocatorDomain domain, PyMemAllocator *allocator)``
|
- ``void PyMem_SetAllocator(PyMemAllocatorDomain domain, PyMemAllocator *allocator)``
|
||||||
|
@ -94,8 +95,7 @@ New Functions and Structures
|
||||||
* Add a new ``PyObjectArenaAllocator`` structure::
|
* Add a new ``PyObjectArenaAllocator`` structure::
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* user context passed as the first argument
|
/* user context passed as the first argument to the 2 functions */
|
||||||
to the 2 functions */
|
|
||||||
void *ctx;
|
void *ctx;
|
||||||
|
|
||||||
/* allocate an arena */
|
/* allocate an arena */
|
||||||
|
@ -111,18 +111,17 @@ New Functions and Structures
|
||||||
- ``void PyObject_GetArenaAllocator(PyObjectArenaAllocator *allocator)``
|
- ``void PyObject_GetArenaAllocator(PyObjectArenaAllocator *allocator)``
|
||||||
- ``void PyObject_SetArenaAllocator(PyObjectArenaAllocator *allocator)``
|
- ``void PyObject_SetArenaAllocator(PyObjectArenaAllocator *allocator)``
|
||||||
|
|
||||||
* Add a new function to setup the debug checks on memory allocators when
|
* Add a new function to reinstall the debug checks on memory allocators when
|
||||||
a memory allocator is replaced:
|
a memory allocator is replaced with ``PyMem_SetAllocator()``:
|
||||||
|
|
||||||
- ``void PyMem_SetupDebugHooks(void)``
|
- ``void PyMem_SetupDebugHooks(void)``
|
||||||
- Install the debug hook on all memory block allocators. The function
|
- Install the debug hooks on all memory block allocators. The function can be
|
||||||
can be called more than once, hooks are not reinstalled if they
|
called more than once, hooks are only installed once.
|
||||||
were already installed.
|
- The function does nothing is Python is not compiled in debug mode.
|
||||||
- The function does nothing is Python is not compiled in debug mode
|
|
||||||
|
|
||||||
* Memory allocators always returns *NULL* if size is greater than
|
* Memory block allocators always return *NULL* if *size* is greater than
|
||||||
``PY_SSIZE_T_MAX``. The check is done before calling the
|
``PY_SSIZE_T_MAX``. The check is done before calling the inner
|
||||||
inner function.
|
function.
|
||||||
|
|
||||||
The *pymalloc* allocator is optimized for objects smaller than 512 bytes
|
The *pymalloc* allocator is optimized for objects smaller than 512 bytes
|
||||||
with a short lifetime. It uses memory mappings with a fixed size of 256
|
with a short lifetime. It uses memory mappings with a fixed size of 256
|
||||||
|
@ -140,8 +139,8 @@ Default allocators:
|
||||||
and ``free()``
|
and ``free()``
|
||||||
|
|
||||||
|
|
||||||
Redesign Debug Checks on Memory Allocators as Hooks
|
Redesign Debug Checks on Memory Block Allocators as Hooks
|
||||||
----------------------------------------------------
|
---------------------------------------------------------
|
||||||
|
|
||||||
Since Python 2.3, Python implements different checks on memory
|
Since Python 2.3, Python implements different checks on memory
|
||||||
allocators in debug mode:
|
allocators in debug mode:
|
||||||
|
@ -157,7 +156,8 @@ In Python 3.3, the checks are installed by replacing ``PyMem_Malloc()``,
|
||||||
``PyMem_Realloc()``, ``PyMem_Free()``, ``PyObject_Malloc()``,
|
``PyMem_Realloc()``, ``PyMem_Free()``, ``PyObject_Malloc()``,
|
||||||
``PyObject_Realloc()`` and ``PyObject_Free()`` using macros. The new
|
``PyObject_Realloc()`` and ``PyObject_Free()`` using macros. The new
|
||||||
allocator allocates a larger buffer and write a pattern to detect buffer
|
allocator allocates a larger buffer and write a pattern to detect buffer
|
||||||
underflow and overflow. It uses the original ``PyObject_Malloc()``
|
underflow, buffer overflow and use after free (fill the buffer with the
|
||||||
|
pattern ``0xDB``). It uses the original ``PyObject_Malloc()``
|
||||||
function to allocate memory. So ``PyMem_Malloc()`` and
|
function to allocate memory. So ``PyMem_Malloc()`` and
|
||||||
``PyMem_Realloc()`` call indirectly ``PyObject_Malloc()`` and
|
``PyMem_Realloc()`` call indirectly ``PyObject_Malloc()`` and
|
||||||
``PyObject_Realloc()``.
|
``PyObject_Realloc()``.
|
||||||
|
@ -178,13 +178,14 @@ Call traces when the hooks are installed (debug mode):
|
||||||
* ``PyObject_Free()`` => ``_PyMem_DebugFree()``
|
* ``PyObject_Free()`` => ``_PyMem_DebugFree()``
|
||||||
=> ``_PyObject_Free()``
|
=> ``_PyObject_Free()``
|
||||||
|
|
||||||
As a result, ``PyMem_Malloc()`` and ``PyMem_Realloc()`` now always call
|
As a result, ``PyMem_Malloc()`` and ``PyMem_Realloc()`` now call
|
||||||
``malloc()`` and ``realloc()``, instead of calling ``PyObject_Malloc()``
|
``malloc()`` and ``realloc()`` in release mode and in debug mode,
|
||||||
and ``PyObject_Realloc()`` in debug mode.
|
instead of calling ``PyObject_Malloc()`` and ``PyObject_Realloc()`` in
|
||||||
|
debug mode.
|
||||||
|
|
||||||
When at least one memory allocator is replaced with
|
When at least one memory allocator is replaced with
|
||||||
``PyMem_SetAllocator()``, the ``PyMem_SetupDebugHooks()`` function must
|
``PyMem_SetAllocator()``, the ``PyMem_SetupDebugHooks()`` function must
|
||||||
be called to install the debug hooks on top on the new allocator.
|
be called to reinstall the debug hooks on top on the new allocator.
|
||||||
|
|
||||||
|
|
||||||
Don't call malloc() directly anymore
|
Don't call malloc() directly anymore
|
||||||
|
@ -195,7 +196,7 @@ Don't call malloc() directly anymore
|
||||||
``PyObject_Realloc()`` falls back on ``PyMem_Realloc()`` instead of
|
``PyObject_Realloc()`` falls back on ``PyMem_Realloc()`` instead of
|
||||||
``realloc()``
|
``realloc()``
|
||||||
|
|
||||||
Replace direct calls to ``malloc()`` with ``PyMem_Malloc()``, or
|
Direct calls to ``malloc()`` are replaced with ``PyMem_Malloc()``, or
|
||||||
``PyMem_RawMalloc()`` if the GIL is not held.
|
``PyMem_RawMalloc()`` if the GIL is not held.
|
||||||
|
|
||||||
Configure external libraries like zlib or OpenSSL to allocate memory
|
Configure external libraries like zlib or OpenSSL to allocate memory
|
||||||
|
@ -205,22 +206,22 @@ Python is embedded in an application.
|
||||||
|
|
||||||
For the "track memory usage" use case, it is important to track memory
|
For the "track memory usage" use case, it is important to track memory
|
||||||
allocated in external libraries to have accurate reports, because these
|
allocated in external libraries to have accurate reports, because these
|
||||||
allocations may be large.
|
allocations can be large (can raise a ``MemoryError`` exception).
|
||||||
|
|
||||||
If an hook is used to the track memory usage, the memory allocated by
|
If an hook is used to the track memory usage, the memory allocated by
|
||||||
``malloc()`` will not be tracked. Remaining ``malloc()`` in external
|
direct calls to ``malloc()`` will not be tracked. Remaining ``malloc()``
|
||||||
libraries like OpenSSL or bz2 may allocate large memory blocks and so
|
in external libraries like OpenSSL or bz2 can allocate large memory
|
||||||
would be missed in memory usage reports.
|
blocks and so would be missed in memory usage reports.
|
||||||
|
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
========
|
========
|
||||||
|
|
||||||
Use case 1: Replace Memory Allocator, keep pymalloc
|
Use case 1: Replace Memory Allocators, keep pymalloc
|
||||||
----------------------------------------------------
|
----------------------------------------------------
|
||||||
|
|
||||||
Dummy example wasting 2 bytes per memory block,
|
Dummy example wasting 2 bytes per memory block,
|
||||||
and 10 bytes per memory mapping::
|
and 10 bytes per *pymalloc* arena::
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
@ -267,6 +268,7 @@ and 10 bytes per memory mapping::
|
||||||
|
|
||||||
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &alloc);
|
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &alloc);
|
||||||
PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &alloc);
|
PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &alloc);
|
||||||
|
/* leave PYMEM_DOMAIN_OBJ unchanged, use pymalloc */
|
||||||
|
|
||||||
arena.ctx = &arena_padding;
|
arena.ctx = &arena_padding;
|
||||||
arena.alloc = my_alloc_arena;
|
arena.alloc = my_alloc_arena;
|
||||||
|
@ -277,7 +279,7 @@ and 10 bytes per memory mapping::
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Use case 2: Replace Memory Allocator, override pymalloc
|
Use case 2: Replace Memory Allocators, override pymalloc
|
||||||
--------------------------------------------------------
|
--------------------------------------------------------
|
||||||
|
|
||||||
If your allocator is optimized for allocations of objects smaller than
|
If your allocator is optimized for allocations of objects smaller than
|
||||||
|
@ -322,11 +324,14 @@ Dummy example wasting 2 bytes per memory block::
|
||||||
PyMem_SetupDebugHooks();
|
PyMem_SetupDebugHooks();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
The *pymalloc* arena does not need to be replaced, because it is no more
|
||||||
|
used by the new allocator.
|
||||||
|
|
||||||
Use case 3: Setup Allocator Hooks
|
|
||||||
---------------------------------
|
|
||||||
|
|
||||||
Example to setup hooks on all memory allocators::
|
Use case 3: Setup Hooks On Memory Block Allocators
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
Example to setup hooks on all memory block allocators::
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
PyMemAllocator raw;
|
PyMemAllocator raw;
|
||||||
|
@ -390,22 +395,23 @@ Example to setup hooks on all memory allocators::
|
||||||
}
|
}
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
``PyMem_SetupDebugHooks()`` does not need to be called because the
|
``PyMem_SetupDebugHooks()`` does not need to be called because
|
||||||
allocator is not replaced: Python debug hooks are installed
|
memory allocator are not replaced: the debug checks on memory
|
||||||
automatically at startup.
|
block allocators are installed automatically at startup.
|
||||||
|
|
||||||
|
|
||||||
Performances
|
Performances
|
||||||
============
|
============
|
||||||
|
|
||||||
|
The implementation of this PEP (issue #3329) has no visible overhead on
|
||||||
|
the Python benchmark suite.
|
||||||
|
|
||||||
Results of the `Python benchmarks suite
|
Results of the `Python benchmarks suite
|
||||||
<http://hg.python.org/benchmarks>`_ (-b 2n3): some tests are 1.04x
|
<http://hg.python.org/benchmarks>`_ (-b 2n3): some tests are 1.04x
|
||||||
faster, some tests are 1.04 slower, significant is between 115 and -191.
|
faster, some tests are 1.04 slower. Results of pybench microbenchmark:
|
||||||
|
"+0.1%" slower globally (diff between -4.9% and +5.6%).
|
||||||
|
|
||||||
Results of pybench benchmark: "+0.1%" slower globally (diff between
|
The full output of benchmarks is attached to the issue #3329.
|
||||||
-4.9% and +5.6%).
|
|
||||||
|
|
||||||
The full reports are attached to the issue #3329.
|
|
||||||
|
|
||||||
|
|
||||||
Rejected Alternatives
|
Rejected Alternatives
|
||||||
|
@ -428,8 +434,9 @@ with:
|
||||||
* ``void PyMem_SetAllocator(PyMemAllocator *allocator)``
|
* ``void PyMem_SetAllocator(PyMemAllocator *allocator)``
|
||||||
* ``void PyObject_SetAllocator(PyMemAllocator *allocator)``
|
* ``void PyObject_SetAllocator(PyMemAllocator *allocator)``
|
||||||
|
|
||||||
With more specific functions, it becomes more difficult to write generic
|
This alternative was rejected because it is not possible to write
|
||||||
code, like reusing the same code for different allocator domains.
|
generic code with more specific functions: code must be duplicated for
|
||||||
|
each memory allocator domain.
|
||||||
|
|
||||||
|
|
||||||
Make PyMem_Malloc() reuse PyMem_RawMalloc() by default
|
Make PyMem_Malloc() reuse PyMem_RawMalloc() by default
|
||||||
|
@ -439,25 +446,25 @@ If ``PyMem_Malloc()`` would call ``PyMem_RawMalloc()`` by default,
|
||||||
calling ``PyMem_SetAllocator(PYMEM_DOMAIN_RAW, alloc)`` would also also
|
calling ``PyMem_SetAllocator(PYMEM_DOMAIN_RAW, alloc)`` would also also
|
||||||
patch ``PyMem_Malloc()`` indirectly.
|
patch ``PyMem_Malloc()`` indirectly.
|
||||||
|
|
||||||
This option was rejected because ``PyMem_SetAllocator()`` would have a
|
This alternative was rejected because ``PyMem_SetAllocator()`` would
|
||||||
different behaviour depending on the domain. Always having the same
|
have a different behaviour depending on the domain. Always having the
|
||||||
behaviour is less error-prone.
|
same behaviour is less error-prone.
|
||||||
|
|
||||||
|
|
||||||
Add a new PYDEBUGMALLOC environment variable
|
Add a new PYDEBUGMALLOC environment variable
|
||||||
--------------------------------------------
|
--------------------------------------------
|
||||||
|
|
||||||
To be able to use the Python builtin debug hooks even when a custom
|
Add a new ``PYDEBUGMALLOC`` environment variable to enable debug checks
|
||||||
memory allocator replaces the default Python allocator, an environment
|
on memory block allocators. The environment variable replaces the new
|
||||||
variable ``PYDEBUGMALLOC`` can be added to setup these debug function
|
function ``PyMem_SetupDebugHooks()`` which is not needed anymore.
|
||||||
hooks, instead of adding the new function ``PyMem_SetupDebugHooks()``.
|
Another advantage is to allow to enable debug checks even in release
|
||||||
If the environment variable is present, ``PyMem_SetRawAllocator()``,
|
mode: debug checks are always compiled, but only enabled when the
|
||||||
``PyMem_SetAllocator()`` and ``PyObject_SetAllocator()`` will reinstall
|
environment variable is present and non-empty.
|
||||||
automatically the hook on top of the new allocator.
|
|
||||||
|
|
||||||
A new environment variable would make the Python initialization even
|
This alternative was rejected because a new environment variable would
|
||||||
more complex. The `PEP 432 <http://www.python.org/dev/peps/pep-0432/>`_
|
make the Python initialization even more complex. The `PEP 432
|
||||||
tries to simply the CPython startup sequence.
|
<http://www.python.org/dev/peps/pep-0432/>`_ tries to simply the CPython
|
||||||
|
startup sequence.
|
||||||
|
|
||||||
|
|
||||||
Use macros to get customizable allocators
|
Use macros to get customizable allocators
|
||||||
|
@ -503,7 +510,7 @@ Example of ``PyMem_Malloc`` macro with the modified
|
||||||
void* _PyMem_MallocTrace(const char *filename, int lineno,
|
void* _PyMem_MallocTrace(const char *filename, int lineno,
|
||||||
size_t size);
|
size_t size);
|
||||||
|
|
||||||
/* need also a function for the Python stable ABI */
|
/* the function is still needed for the Python stable ABI */
|
||||||
void* PyMem_Malloc(size_t size);
|
void* PyMem_Malloc(size_t size);
|
||||||
|
|
||||||
#define PyMem_Malloc(size) \
|
#define PyMem_Malloc(size) \
|
||||||
|
@ -527,19 +534,19 @@ In Python 3.3, when Python is compiled in debug mode, ``PyMem_Malloc()``
|
||||||
calls indirectly ``PyObject_Malloc()`` which requires the GIL to be
|
calls indirectly ``PyObject_Malloc()`` which requires the GIL to be
|
||||||
held. That's why ``PyMem_Malloc()`` must be called with the GIL held.
|
held. That's why ``PyMem_Malloc()`` must be called with the GIL held.
|
||||||
|
|
||||||
This PEP proposes changes ``PyMem_Malloc()``: it now always call
|
This PEP changes ``PyMem_Malloc()``: it now always call ``malloc()``.
|
||||||
``malloc()``. The "GIL must be held" restriction can be removed from
|
The "GIL must be held" restriction could be removed from
|
||||||
``PyMem_Malloc()``.
|
``PyMem_Malloc()``.
|
||||||
|
|
||||||
This alternative was rejected because allowing to call
|
This alternative was rejected because allowing to call
|
||||||
``PyMem_Malloc()`` without holding the GIL might break applications
|
``PyMem_Malloc()`` without holding the GIL can break applications
|
||||||
which setup their own allocators or allocator hooks. Holding the GIL is
|
which setup their own allocators or allocator hooks. Holding the GIL is
|
||||||
convinient to develop a custom allocator: no need to care of other
|
convinient to develop a custom allocator: no need to care of other
|
||||||
threads. It is also convinient for a debug allocator hook: Python
|
threads. It is also convinient for a debug allocator hook: Python
|
||||||
internal objects can be safetly inspected.
|
internal objects can be safetly inspected.
|
||||||
|
|
||||||
Calling ``PyGILState_Ensure()`` in
|
Calling ``PyGILState_Ensure()`` in
|
||||||
a memory allocator may have unexpected behaviour, especially at Python
|
a memory allocator has unexpected behaviour, especially at Python
|
||||||
startup and at creation of a new Python thread state.
|
startup and at creation of a new Python thread state.
|
||||||
|
|
||||||
|
|
||||||
|
@ -552,13 +559,14 @@ held. Otherwise, keep ``malloc()`` unchanged.
|
||||||
The ``PyMem_Malloc()`` is used without the GIL held in some Python
|
The ``PyMem_Malloc()`` is used without the GIL held in some Python
|
||||||
functions. For example, the ``main()`` and ``Py_Main()`` functions of
|
functions. For example, the ``main()`` and ``Py_Main()`` functions of
|
||||||
Python call ``PyMem_Malloc()`` whereas the GIL do not exist yet. In this
|
Python call ``PyMem_Malloc()`` whereas the GIL do not exist yet. In this
|
||||||
case, ``PyMem_Malloc()`` should be replaced with ``malloc()`` (or
|
case, ``PyMem_Malloc()`` would be replaced with ``malloc()`` (or
|
||||||
``PyMem_RawMalloc()``).
|
``PyMem_RawMalloc()``).
|
||||||
|
|
||||||
If an hook is used to the track memory usage, the memory allocated by
|
This alternative was rejected because ``PyMem_RawMalloc()`` is required
|
||||||
direct calls to ``malloc()`` will not be tracked. External libraries
|
for accurate reports of the memory usage. When a debug hook is used to
|
||||||
like OpenSSL or bz2 should not call ``malloc()`` directly, so large
|
track the memory usage, the memory allocated by direct calls to
|
||||||
allocated will be included in memory usage reports.
|
``malloc()`` cannot be tracked. ``PyMem_RawMalloc()`` can be hooked and
|
||||||
|
so all the memory allocated by Python can be tracked.
|
||||||
|
|
||||||
|
|
||||||
Use existing debug tools to analyze the memory
|
Use existing debug tools to analyze the memory
|
||||||
|
@ -571,11 +579,11 @@ examples: `Valgrind <http://valgrind.org/>`_, `Purify
|
||||||
<http://www.nongnu.org/failmalloc/>`_, etc.
|
<http://www.nongnu.org/failmalloc/>`_, etc.
|
||||||
|
|
||||||
The problem is to retrieve the Python object related to a memory pointer
|
The problem is to retrieve the Python object related to a memory pointer
|
||||||
to read its type and/or content. Another issue is to retrieve the
|
to read its type and/or its content. Another issue is to retrieve the
|
||||||
location of the memory allocation: the C backtrace is usually useless
|
location of the memory allocation: the C backtrace is usually useless
|
||||||
(same reasoning than macros using ``__FILE__`` and ``__LINE__``), the
|
(same reasoning than macros using ``__FILE__`` and ``__LINE__``, see
|
||||||
Python filename and line number (or even the Python traceback) is more
|
`Pass the C filename and line number`_), the Python filename and line
|
||||||
useful.
|
number (or even the Python traceback) is more useful.
|
||||||
|
|
||||||
This alternative was rejected because classic tools are unable to
|
This alternative was rejected because classic tools are unable to
|
||||||
introspect Python internals to collect such information. Being able to
|
introspect Python internals to collect such information. Being able to
|
||||||
|
@ -586,8 +594,8 @@ lot of useful data from Python internals.
|
||||||
Add a msize() function
|
Add a msize() function
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
Add another field to ``PyMemAllocator`` and ``PyObjectArenaAllocator``
|
Add another function to ``PyMemAllocator`` and
|
||||||
structures::
|
``PyObjectArenaAllocator`` structures::
|
||||||
|
|
||||||
size_t msize(void *ptr);
|
size_t msize(void *ptr);
|
||||||
|
|
||||||
|
@ -607,8 +615,8 @@ The additional ``msize()`` function was rejected because only few
|
||||||
platforms implement it. For example, Linux with the GNU libc does not
|
platforms implement it. For example, Linux with the GNU libc does not
|
||||||
provide a function to get the size of a memory block. ``msize()`` is not
|
provide a function to get the size of a memory block. ``msize()`` is not
|
||||||
currently used in the Python source code. The function is only used to
|
currently used in the Python source code. The function is only used to
|
||||||
track the memory usage, but makes the API more complex. A debug hook can
|
track the memory usage, and makes the API more complex. A debug hook can
|
||||||
implemente the function internally, there is no need to add it to
|
implement the function internally, there is no need to add it to
|
||||||
``PyMemAllocator`` and ``PyObjectArenaAllocator`` structures.
|
``PyMemAllocator`` and ``PyObjectArenaAllocator`` structures.
|
||||||
|
|
||||||
|
|
||||||
|
@ -653,17 +661,19 @@ Libraries used by Python:
|
||||||
* lzma: `LZMA SDK - How to Use
|
* lzma: `LZMA SDK - How to Use
|
||||||
<http://www.asawicki.info/news_1368_lzma_sdk_-_how_to_use.html>`_,
|
<http://www.asawicki.info/news_1368_lzma_sdk_-_how_to_use.html>`_,
|
||||||
pass an opaque pointer
|
pass an opaque pointer
|
||||||
* lipmpdec doesn't have this extra *ctx* parameter
|
* lipmpdec: no opaque pointer (classic malloc API)
|
||||||
|
|
||||||
Other libraries:
|
Other libraries:
|
||||||
|
|
||||||
* glib: `g_mem_set_vtable()
|
* glib: `g_mem_set_vtable()
|
||||||
<http://developer.gnome.org/glib/unstable/glib-Memory-Allocation.html#g-mem-set-vtable>`_
|
<http://developer.gnome.org/glib/unstable/glib-Memory-Allocation.html#g-mem-set-vtable>`_
|
||||||
* libxml2: `xmlGcMemSetup() <http://xmlsoft.org/html/libxml-xmlmemory.html>`_,
|
* libxml2:
|
||||||
|
`xmlGcMemSetup() <http://xmlsoft.org/html/libxml-xmlmemory.html>`_,
|
||||||
global
|
global
|
||||||
* Oracle's OCI: `Oracle Call Interface Programmer's Guide,
|
* Oracle's OCI: `Oracle Call Interface Programmer's Guide,
|
||||||
Release 2 (9.2)
|
Release 2 (9.2)
|
||||||
<http://docs.oracle.com/cd/B10501_01/appdev.920/a96584/oci15re4.htm>`_
|
<http://docs.oracle.com/cd/B10501_01/appdev.920/a96584/oci15re4.htm>`_,
|
||||||
|
pass an opaque pointer
|
||||||
|
|
||||||
See also the `GNU libc: Memory Allocation Hooks
|
See also the `GNU libc: Memory Allocation Hooks
|
||||||
<http://www.gnu.org/software/libc/manual/html_node/Hooks-for-Malloc.html>`_.
|
<http://www.gnu.org/software/libc/manual/html_node/Hooks-for-Malloc.html>`_.
|
||||||
|
@ -676,30 +686,30 @@ The C standard library provides the well known ``malloc()`` function.
|
||||||
Its implementation depends on the platform and of the C library. The GNU
|
Its implementation depends on the platform and of the C library. The GNU
|
||||||
C library uses a modified ptmalloc2, based on "Doug Lea's Malloc"
|
C library uses a modified ptmalloc2, based on "Doug Lea's Malloc"
|
||||||
(dlmalloc). FreeBSD uses `jemalloc
|
(dlmalloc). FreeBSD uses `jemalloc
|
||||||
<http://www.canonware.com/jemalloc/>`_. Google provides tcmalloc which
|
<http://www.canonware.com/jemalloc/>`_. Google provides *tcmalloc* which
|
||||||
is part of `gperftools <http://code.google.com/p/gperftools/>`_.
|
is part of `gperftools <http://code.google.com/p/gperftools/>`_.
|
||||||
|
|
||||||
``malloc()`` uses two kinds of memory: heap and memory mappings. Memory
|
``malloc()`` uses two kinds of memory: heap and memory mappings. Memory
|
||||||
mappings are usually used for large allocations (ex: larger than 256
|
mappings are usually used for large allocations (ex: larger than 256
|
||||||
KB), whereas the heap is used for small allocations.
|
KB), whereas the heap is used for small allocations.
|
||||||
|
|
||||||
On UNIX, the heap is handled by ``brk()`` and ``sbrk()`` system calls on
|
On UNIX, the heap is handled by ``brk()`` and ``sbrk()`` system calls,
|
||||||
Linux, and it is contiguous. On Windows, the heap is handled by
|
and it is contiguous. On Windows, the heap is handled by
|
||||||
``HeapAlloc()`` and may be discontiguous. Memory mappings are handled by
|
``HeapAlloc()`` and can be discontiguous. Memory mappings are handled by
|
||||||
``mmap()`` on UNIX and ``VirtualAlloc()`` on Windows, they may be
|
``mmap()`` on UNIX and ``VirtualAlloc()`` on Windows, they can be
|
||||||
discontiguous.
|
discontiguous.
|
||||||
|
|
||||||
Releasing a memory mapping gives back immediatly the memory to the
|
Releasing a memory mapping gives back immediatly the memory to the
|
||||||
system. On UNIX, heap memory is only given back to the system if it is
|
system. On UNIX, the heap memory is only given back to the system if the
|
||||||
at the end of the heap. Otherwise, the memory will only be given back to
|
released block is located at the end of the heap. Otherwise, the memory
|
||||||
the system when all the memory located after the released memory are
|
will only be given back to the system when all the memory located after
|
||||||
also released.
|
the released memory is also released.
|
||||||
|
|
||||||
To allocate memory in the heap, the allocator tries to reuse free space.
|
To allocate memory on the heap, an allocator tries to reuse free space.
|
||||||
If there is no contiguous space big enough, the heap must be increased,
|
If there is no contiguous space big enough, the heap must be enlarged,
|
||||||
even if we have more free space than required size. This issue is
|
even if there is more free space than required size. This issue is
|
||||||
called the "memory fragmentation": the memory usage seen by the system
|
called the "memory fragmentation": the memory usage seen by the system
|
||||||
may be much higher than real usage. On Windows, ``HeapAlloc()`` creates
|
is higher than real usage. On Windows, ``HeapAlloc()`` creates
|
||||||
a new memory mapping with ``VirtualAlloc()`` if there is not enough free
|
a new memory mapping with ``VirtualAlloc()`` if there is not enough free
|
||||||
contiguous memory.
|
contiguous memory.
|
||||||
|
|
||||||
|
@ -730,8 +740,8 @@ CPython issues related to memory allocation:
|
||||||
<http://bugs.python.org/issue3329>`_
|
<http://bugs.python.org/issue3329>`_
|
||||||
* `Issue #13483: Use VirtualAlloc to allocate memory arenas
|
* `Issue #13483: Use VirtualAlloc to allocate memory arenas
|
||||||
<http://bugs.python.org/issue13483>`_
|
<http://bugs.python.org/issue13483>`_
|
||||||
* `Issue #16742: PyOS_Readline drops GIL and calls PyOS_StdioReadline, which
|
* `Issue #16742: PyOS_Readline drops GIL and calls PyOS_StdioReadline,
|
||||||
isn't thread safe <http://bugs.python.org/issue16742>`_
|
which isn't thread safe <http://bugs.python.org/issue16742>`_
|
||||||
* `Issue #18203: Replace calls to malloc() with PyMem_Malloc() or
|
* `Issue #18203: Replace calls to malloc() with PyMem_Malloc() or
|
||||||
PyMem_RawMalloc() <http://bugs.python.org/issue18203>`_
|
PyMem_RawMalloc() <http://bugs.python.org/issue18203>`_
|
||||||
* `Issue #18227: Use Python memory allocators in external libraries like
|
* `Issue #18227: Use Python memory allocators in external libraries like
|
||||||
|
|
Loading…
Reference in New Issue