* add PyMemAllocatorDomain enum: PYALLOC_PYMEM_RAW, PYALLOC_PYMEM or
   PYALLOC_PYOBJECT
 * rename:

   - PyMemBlockAllocator structure => PyMemAllocator
   - PyMem_GetMappingAllocator() => PyObject_GetArenaAllocator()
   - PyMemMappingAllocator structure => PyObjectArenaAllocator
   - PyMem_SetMappingAllocator() => PyObject_SetArenaAllocator()

 * group get/set functions to only keep 2 functions:
   PyMem_GetAllocator() and PyMem_SetAllocator()
 * PyMem_RawMalloc(0) now calls malloc(1) to have a well defined behaviour
 * PYALLOC_PYMEM_RAW and PYALLOC_PYMEM are now using exactly the same allocator
 * Add more references for external libraries
This commit is contained in:
Victor Stinner 2013-06-20 13:20:58 +02:00
parent f4a21c42e6
commit 682a7fe994
1 changed files with 157 additions and 144 deletions

View File

@ -40,18 +40,20 @@ Use cases:
Proposal Proposal
======== ========
API changes New functions and new structure
----------- -------------------------------
* Add new GIL-free (no need to hold the GIL) memory allocator functions: * Add a new GIL-free (no need to hold the GIL) memory allocator:
- ``void* PyMem_RawMalloc(size_t size)`` - ``void* PyMem_RawMalloc(size_t size)``
- ``void* PyMem_RawRealloc(void *ptr, size_t new_size)`` - ``void* PyMem_RawRealloc(void *ptr, size_t new_size)``
- ``void PyMem_RawFree(void *ptr)`` - ``void PyMem_RawFree(void *ptr)``
- the behaviour of requesting zero bytes is not defined: return *NULL* - The newly allocated memory will not have been initialized in any
or a distinct non-*NULL* pointer depending on the platform. way.
- Requesting zero bytes returns a distinct non-*NULL* pointer if
possible, as if ``PyMem_Malloc(1)`` had been called instead.
* Add a new ``PyMemBlockAllocator`` structure:: * Add a new ``PyMemAllocator`` structure::
typedef struct { typedef struct {
/* user context passed as the first argument /* user context passed as the first argument
@ -66,69 +68,70 @@ API changes
/* release a memory block */ /* release a memory block */
void (*free) (void *ctx, void *ptr); void (*free) (void *ctx, void *ptr);
} PyMemBlockAllocator; } PyMemAllocator;
* Add new functions to get and set internal functions of * Add a new ``PyMemAllocatorDomain`` enum to choose the Python
``PyMem_RawMalloc()``, ``PyMem_RawRealloc()`` and ``PyMem_RawFree()``: allocator domain. Domains:
- ``void PyMem_GetRawAllocator(PyMemBlockAllocator *allocator)`` - ``PYALLOC_PYMEM_RAW``: ``PyMem_RawMalloc()``, ``PyMem_RawRealloc()``
- ``void PyMem_SetRawAllocator(PyMemBlockAllocator *allocator)`` and ``PyMem_RawRealloc()``
- default allocator: ``malloc()``, ``realloc()``, ``free()``
* Add new functions to get and set internal functions of - ``PYALLOC_PYMEM``: ``PyMem_Malloc()``, ``PyMem_Realloc()`` and
``PyMem_Malloc()``, ``PyMem_Realloc()`` and ``PyMem_Free()``: ``PyMem_Realloc()``
- ``void PyMem_GetAllocator(PyMemBlockAllocator *allocator)`` - ``PYALLOC_PYOBJECT``: ``PyObject_Malloc()``, ``PyObject_Realloc()``
- ``void PyMem_SetAllocator(PyMemBlockAllocator *allocator)`` and ``PyObject_Realloc()``
- ``malloc(ctx, 0)`` and ``realloc(ctx, ptr, 0)`` must not return
*NULL*: it would be treated as an error.
- default allocator: ``malloc()``, ``realloc()``, ``free()``;
``PyMem_Malloc(0)`` calls ``malloc(1)``
and ``PyMem_Realloc(NULL, 0)`` calls ``realloc(NULL, 1)``
* Add new functions to get and set internal functions of * Add new functions to get and set memory allocators:
``PyObject_Malloc()``, ``PyObject_Realloc()`` and
``PyObject_Free()``:
- ``void PyObject_GetAllocator(PyMemBlockAllocator *allocator)`` - ``void PyMem_GetAllocator(PyMemAllocatorDomain domain, PyMemAllocator *allocator)``
- ``void PyObject_SetAllocator(PyMemBlockAllocator *allocator)`` - ``void PyMem_SetAllocator(PyMemAllocatorDomain domain, PyMemAllocator *allocator)``
- ``malloc(ctx, 0)`` and ``realloc(ctx, ptr, 0)`` must not return - The new allocator must return a distinct non-*NULL* pointer when
*NULL*: it would be treated as an error. requesting zero bytes
- default allocator: the *pymalloc* allocator
* Add a new ``PyMemMappingAllocator`` 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 a memory mapping */ /* allocate an arena */
void* (*alloc) (void *ctx, size_t size); void* (*alloc) (void *ctx, size_t size);
/* release a memory mapping */ /* release an arena */
void (*free) (void *ctx, void *ptr, size_t size); void (*free) (void *ctx, void *ptr, size_t size);
} PyMemMappingAllocator; } PyObjectArenaAllocator;
* Add a new function to get and set the memory mapping allocator: * Add new functions to get and set the arena allocator used by
*pymalloc*:
- ``void PyMem_GetMappingAllocator(PyMemMappingAllocator *allocator)`` - ``void PyObject_GetArenaAllocator(PyObjectArenaAllocator *allocator)``
- ``void PyMem_SetMappingAllocator(PyMemMappingAllocator *allocator)`` - ``void PyObject_SetArenaAllocator(PyObjectArenaAllocator *allocator)``
- Currently, this allocator is only used internally by *pymalloc* to
allocate arenas.
* Add a new function to setup the builtin Python debug hooks when memory * Add a new function to setup the builtin Python debug hooks when a
allocators are replaced: memory allocator is replaced:
- ``void PyMem_SetupDebugHooks(void)`` - ``void PyMem_SetupDebugHooks(void)``
- the function does nothing is Python is compiled not compiled in - the function does nothing is Python is not compiled in debug mode
debug mode
* The following memory allocators always returns *NULL* if size is * Memory allocators always returns *NULL* if size is greater than
greater than ``PY_SSIZE_T_MAX`` (check before calling the internal ``PY_SSIZE_T_MAX``. The check is done before calling the
function): ``PyMem_RawMalloc()``, ``PyMem_RawRealloc()``, inner function.
``PyMem_Malloc()``, ``PyMem_Realloc()``, ``PyObject_Malloc()``,
``PyObject_Realloc()``. 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
KB called "arenas".
Default allocators:
* ``PYALLOC_PYMEM_RAW``, ``PYALLOC_PYMEM``: ``malloc()``,
``realloc()``, ``free()`` (and *ctx* is NULL); call ``malloc(1)`` when
requesting zero bytes
* ``PYALLOC_PYOBJECT``: *pymalloc* allocator which fall backs on
``PyMem_Malloc()`` for allocations larger than 512 bytes
* *pymalloc* arena allocator: ``mmap()``, ``munmap()`` (and *ctx* is
NULL), or ``malloc()`` and ``free()`` if ``mmap()`` is not available
The builtin Python debug hooks were introduced in Python 2.3 and The builtin Python debug hooks were introduced in Python 2.3 and
implement the following checks: implement the following checks:
@ -141,23 +144,34 @@ implement the following checks:
* Detect write after the end of the buffer (buffer overflow) * Detect write after the end of the buffer (buffer overflow)
Other changes Don't call malloc() directly anymore
------------- ------------------------------------
* ``PyMem_Malloc()`` and ``PyMem_Realloc()`` always call ``malloc()`` ``PyMem_Malloc()`` and ``PyMem_Realloc()`` always call ``malloc()`` and
and ``realloc()``, instead of calling ``PyObject_Malloc()`` and ``realloc()``, instead of calling ``PyObject_Malloc()`` and
``PyObject_Realloc()`` in debug mode ``PyObject_Realloc()`` in debug mode.
* ``PyObject_Malloc()`` falls back on ``PyMem_Malloc()`` instead of ``PyObject_Malloc()`` falls back on ``PyMem_Malloc()`` instead of
``malloc()`` if size is greater or equal than ``malloc()`` if size is greater or equal than 512 bytes, and
``SMALL_REQUEST_THRESHOLD`` (512 bytes), and ``PyObject_Realloc()`` ``PyObject_Realloc()`` falls back on ``PyMem_Realloc()`` instead of
falls back on ``PyMem_Realloc()`` instead of ``realloc()`` ``realloc()``
* Replace direct calls to ``malloc()`` with ``PyMem_Malloc()``, or Replace direct calls to ``malloc()`` 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
using ``PyMem_RawMalloc()`` using ``PyMem_Malloc()`` or ``PyMem_RawMalloc()``. If the allocator of a
library can only be replaced globally, the allocator is not replaced if
Python is embedded in an application.
For the "track memory usage" use case, it is important to track memory
allocated in external libraries to have accurate reports, because these
allocations may be large.
If an hook is used to the track memory usage, the memory allocated by
``malloc()`` will not be tracked. Remaining ``malloc()`` in external
libraries like OpenSSL or bz2 may allocate large memory blocks and so
would be missed in memory usage reports.
Examples Examples
@ -171,8 +185,8 @@ and 10 bytes per memory mapping::
#include <stdlib.h> #include <stdlib.h>
int block_padding = 2; int alloc_padding = 2;
int mapping_padding = 10; int arena_padding = 10;
void* my_malloc(void *ctx, size_t size) void* my_malloc(void *ctx, size_t size)
{ {
@ -191,49 +205,49 @@ and 10 bytes per memory mapping::
free(ptr); free(ptr);
} }
void* my_alloc_mapping(void *ctx, size_t size) void* my_alloc_arena(void *ctx, size_t size)
{ {
int padding = *(int *)ctx; int padding = *(int *)ctx;
return malloc(size + padding); return malloc(size + padding);
} }
void my_free_mapping(void *ctx, void *ptr, size_t size) void my_free_arena(void *ctx, void *ptr, size_t size)
{ {
free(ptr); free(ptr);
} }
void setup_custom_allocator(void) void setup_custom_allocator(void)
{ {
PyMemBlockAllocator block; PyMemAllocator alloc;
PyMemMappingAllocator mapping; PyObjectArenaAllocator arena;
block.ctx = &block_padding; alloc.ctx = &alloc_padding;
block.malloc = my_malloc; alloc.malloc = my_malloc;
block.realloc = my_realloc; alloc.realloc = my_realloc;
block.free = my_free; alloc.free = my_free;
PyMem_SetRawAllocator(&block); PyMem_SetAllocator(PYALLOC_PYMEM_RAW, &alloc);
PyMem_SetAllocator(&block); PyMem_SetAllocator(PYALLOC_PYMEM, &alloc);
mapping.ctx = &mapping_padding; arena.ctx = &arena_padding;
mapping.alloc = my_alloc_mapping; arena.alloc = my_alloc_arena;
mapping.free = my_free_mapping; arena.free = my_free_arena;
PyMem_SetMappingAllocator(mapping); PyObject_SetArenaAllocator(&arena);
PyMem_SetupDebugHooks(); PyMem_SetupDebugHooks();
} }
.. warning:: .. warning::
Remove the call ``PyMem_SetRawAllocator(&alloc)`` if the new Remove the call ``PyMem_SetAllocator(PYALLOC_PYMEM_RAW, &alloc)`` if
allocator are not thread-safe. the new allocator is not thread-safe.
Use case 2: Replace Memory Allocator, override pymalloc Use case 2: Replace Memory Allocator, override pymalloc
-------------------------------------------------------- --------------------------------------------------------
If your allocator is optimized for allocation of small objects (less If your allocator is optimized for allocations of objects smaller than
than 512 bytes) with a short lifetime, pymalloc can be overriden 512 bytes with a short lifetime, pymalloc can be overriden (replace
(replace ``PyObject_Malloc()``). ``PyObject_Malloc()``).
Dummy example wasting 2 bytes per memory block:: Dummy example wasting 2 bytes per memory block::
@ -260,22 +274,22 @@ Dummy example wasting 2 bytes per memory block::
void setup_custom_allocator(void) void setup_custom_allocator(void)
{ {
PyMemBlockAllocator alloc; PyMemAllocator alloc;
alloc.ctx = &padding; alloc.ctx = &padding;
alloc.malloc = my_malloc; alloc.malloc = my_malloc;
alloc.realloc = my_realloc; alloc.realloc = my_realloc;
alloc.free = my_free; alloc.free = my_free;
PyMem_SetRawAllocator(&alloc); PyMem_SetAllocator(PYALLOC_PYMEM_RAW, &alloc);
PyMem_SetAllocator(&alloc); PyMem_SetAllocator(PYALLOC_PYMEM, &alloc);
PyObject_SetAllocator(&alloc); PyMem_SetAllocator(PYALLOC_PYOBJECT, &alloc);
PyMem_SetupDebugHooks(); PyMem_SetupDebugHooks();
} }
.. warning:: .. warning::
Remove the call ``PyMem_SetRawAllocator(&alloc)`` if the new Remove the call ``PyMem_SetAllocator(PYALLOC_PYMEM_RAW, &alloc)`` if
allocator are not thread-safe. the new allocator is not thread-safe.
@ -285,15 +299,15 @@ Use case 3: Setup Allocator Hooks
Example to setup hooks on all memory allocators:: Example to setup hooks on all memory allocators::
struct { struct {
PyMemBlockAllocator raw; PyMemAllocator raw;
PyMemBlockAllocator mem; PyMemAllocator mem;
PyMemBlockAllocator obj; PyMemAllocator obj;
/* ... */ /* ... */
} hook; } hook;
static void* hook_malloc(void *ctx, size_t size) static void* hook_malloc(void *ctx, size_t size)
{ {
PyMemBlockAllocator *alloc = (PyMemBlockAllocator *)ctx; PyMemAllocator *alloc = (PyMemAllocator *)ctx;
/* ... */ /* ... */
ptr = alloc->malloc(alloc->ctx, size); ptr = alloc->malloc(alloc->ctx, size);
/* ... */ /* ... */
@ -302,7 +316,7 @@ Example to setup hooks on all memory allocators::
static void* hook_realloc(void *ctx, void *ptr, size_t new_size) static void* hook_realloc(void *ctx, void *ptr, size_t new_size)
{ {
PyMemBlockAllocator *alloc = (PyMemBlockAllocator *)ctx; PyMemAllocator *alloc = (PyMemAllocator *)ctx;
void *ptr2; void *ptr2;
/* ... */ /* ... */
ptr2 = alloc->realloc(alloc->ctx, ptr, new_size); ptr2 = alloc->realloc(alloc->ctx, ptr, new_size);
@ -312,7 +326,7 @@ Example to setup hooks on all memory allocators::
static void hook_free(void *ctx, void *ptr) static void hook_free(void *ctx, void *ptr)
{ {
PyMemBlockAllocator *alloc = (PyMemBlockAllocator *)ctx; PyMemAllocator *alloc = (PyMemAllocator *)ctx;
/* ... */ /* ... */
alloc->free(alloc->ctx, ptr); alloc->free(alloc->ctx, ptr);
/* ... */ /* ... */
@ -320,7 +334,7 @@ Example to setup hooks on all memory allocators::
void setup_hooks(void) void setup_hooks(void)
{ {
PyMemBlockAllocator alloc; PyMemAllocator alloc;
static int installed = 0; static int installed = 0;
if (installed) if (installed)
@ -330,27 +344,28 @@ Example to setup hooks on all memory allocators::
alloc.malloc = hook_malloc; alloc.malloc = hook_malloc;
alloc.realloc = hook_realloc; alloc.realloc = hook_realloc;
alloc.free = hook_free; alloc.free = hook_free;
PyMem_GetAllocator(PYALLOC_PYMEM_RAW, &hook.raw);
PyMem_GetAllocator(PYALLOC_PYMEM, &hook.mem);
PyMem_GetAllocator(PYALLOC_PYOBJECT, &hook.obj);
PyMem_GetRawAllocator(&hook.raw);
alloc.ctx = &hook.raw; alloc.ctx = &hook.raw;
PyMem_SetRawAllocator(&alloc); PyMem_SetAllocator(PYALLOC_PYMEM_RAW, &alloc);
PyMem_GetAllocator(&hook.mem);
alloc.ctx = &hook.mem; alloc.ctx = &hook.mem;
PyMem_SetAllocator(&alloc); PyMem_SetAllocator(PYALLOC_PYMEM, &alloc);
PyObject_GetAllocator(&hook.obj);
alloc.ctx = &hook.obj; alloc.ctx = &hook.obj;
PyObject_SetAllocator(&alloc); PyMem_SetAllocator(PYALLOC_PYOBJECT, &alloc);
} }
.. warning:: .. warning::
Remove the call ``PyMem_SetRawAllocator(&alloc)`` if hooks are not Remove the call ``PyMem_SetAllocator(PYALLOC_PYMEM_RAW, &alloc)`` if
thread-safe. hooks are not thread-safe.
.. note:: .. note::
``PyMem_SetupDebugHooks()`` does not need to be called: Python debug ``PyMem_SetupDebugHooks()`` does not need to be called because the
hooks are installed automatically at startup. allocator is not replaced: Python debug hooks are installed
automatically at startup.
Performances Performances
@ -369,32 +384,22 @@ The full reports are attached to the issue #3329.
Alternatives Alternatives
============ ============
Only one get/set function for block allocators More specific functions to get/set memory allocators
---------------------------------------------- ----------------------------------------------------
Replace the 6 functions: Replace the 2 functions:
* ``void PyMem_GetRawAllocator(PyMemBlockAllocator *allocator)`` * ``void PyMem_GetAllocator(PyMemAllocatorDomain domain, PyMemAllocator *allocator)``
* ``void PyMem_GetAllocator(PyMemBlockAllocator *allocator)`` * ``void PyMem_SetAllocator(PyMemAllocatorDomain domain, PyMemAllocator *allocator)``
* ``void PyObject_GetAllocator(PyMemBlockAllocator *allocator)``
* ``void PyMem_SetRawAllocator(PyMemBlockAllocator *allocator)``
* ``void PyMem_SetAllocator(PyMemBlockAllocator *allocator)``
* ``void PyObject_SetAllocator(PyMemBlockAllocator *allocator)``
with 2 functions with an additional *domain* argument: with:
* ``int PyMem_GetBlockAllocator(int domain, PyMemBlockAllocator *allocator)`` * ``void PyMem_GetRawAllocator(PyMemAllocator *allocator)``
* ``int PyMem_SetBlockAllocator(int domain, PyMemBlockAllocator *allocator)`` * ``void PyMem_GetAllocator(PyMemAllocator *allocator)``
* ``void PyObject_GetAllocator(PyMemAllocator *allocator)``
These functions return 0 on success, or -1 if the domain is unknown. * ``void PyMem_SetRawAllocator(PyMemAllocator *allocator)``
* ``void PyMem_SetAllocator(PyMemAllocator *allocator)``
where domain is one of these values: * ``void PyObject_SetAllocator(PyMemAllocator *allocator)``
* ``PYALLOC_PYMEM``
* ``PYALLOC_PYMEM_RAW``
* ``PYALLOC_PYOBJECT``
Drawback: the caller has to check if the result is 0, or handle the error.
Make PyMem_Malloc() reuse PyMem_RawMalloc() by default Make PyMem_Malloc() reuse PyMem_RawMalloc() by default
@ -404,12 +409,6 @@ Make PyMem_Malloc() reuse PyMem_RawMalloc() by default
calling ``PyMem_SetRawAllocator()`` would also also patch calling ``PyMem_SetRawAllocator()`` would also also patch
``PyMem_Malloc()`` indirectly. ``PyMem_Malloc()`` indirectly.
.. note::
In the implementation of this PEP (issue #3329),
``PyMem_RawMalloc(0)`` calls ``malloc(0)``,
whereas ``PyMem_Malloc(0)`` calls ``malloc(1)``.
Add a new PYDEBUGMALLOC environment variable Add a new PYDEBUGMALLOC environment variable
-------------------------------------------- --------------------------------------------
@ -445,7 +444,7 @@ Define allocator functions as macros using ``__FILE__`` and ``__LINE__``
to get the C filename and line number of a memory allocation. to get the C filename and line number of a memory allocation.
Example of ``PyMem_Malloc`` macro with the modified Example of ``PyMem_Malloc`` macro with the modified
``PyMemBlockAllocator`` structure:: ``PyMemAllocator`` structure::
typedef struct { typedef struct {
/* user context passed as the first argument /* user context passed as the first argument
@ -463,7 +462,7 @@ Example of ``PyMem_Malloc`` macro with the modified
/* release a memory block */ /* release a memory block */
void (*free) (void *ctx, const char *filename, int lineno, void (*free) (void *ctx, const char *filename, int lineno,
void *ptr); void *ptr);
} PyMemBlockAllocator; } PyMemAllocator;
void* _PyMem_MallocTrace(const char *filename, int lineno, void* _PyMem_MallocTrace(const char *filename, int lineno,
size_t size); size_t size);
@ -485,12 +484,12 @@ changes add too much complexity for a little gain.
GIL-free PyMem_Malloc() GIL-free PyMem_Malloc()
----------------------- -----------------------
When Python is compiled in debug mode, ``PyMem_Malloc()`` calls In Python 3.3, when Python is compiled in debug mode, ``PyMem_Malloc()``
indirectly ``PyObject_Malloc()`` which requires the GIL to be held. calls indirectly ``PyObject_Malloc()`` which requires the GIL to be
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 to "fix" ``PyMem_Malloc()`` to make it always call This PEP proposes changes ``PyMem_Malloc()``: it now always call
``malloc()``. So the "GIL must be held" restriction may be removed from ``malloc()``. The "GIL must be held" restriction can be removed from
``PyMem_Malloc()``. ``PyMem_Malloc()``.
Allowing to call ``PyMem_Malloc()`` without holding the GIL might break Allowing to call ``PyMem_Malloc()`` without holding the GIL might break
@ -516,9 +515,10 @@ 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()`` should be replaced with ``malloc()`` (or
``PyMem_RawMalloc()``). ``PyMem_RawMalloc()``).
If an hook is used to the track memory usage, the ``malloc()`` memory If an hook is used to the track memory usage, the memory allocated by
will not be seen. Remaining ``malloc()`` may allocate a lot of memory direct calls to ``malloc()`` will not be tracked. External libraries
and so would be missed in reports. like OpenSSL or bz2 should not call ``malloc()`` directly, so large
allocated will be included in memory usage reports.
Use existing debug tools to analyze the memory Use existing debug tools to analyze the memory
@ -545,8 +545,7 @@ GIL held allow to collect a lot of useful data from Python internals.
Add msize() Add msize()
----------- -----------
Add another field to ``PyMemBlockAllocator`` and Add another field to ``PyMemAllocator`` and ``PyObjectArenaAllocator``::
``PyMemMappingAllocator``::
size_t msize(void *ptr); size_t msize(void *ptr);
@ -574,6 +573,8 @@ It is likely for an allocator hook to be reused for
depending on the allocator. The context is a convenient way to reuse the depending on the allocator. The context is a convenient way to reuse the
same custom allocator or hook for different Python allocators. same custom allocator or hook for different Python allocators.
In C++, the context can be used to pass *this*.
External libraries External libraries
================== ==================
@ -589,6 +590,15 @@ Libraries used by Python:
* expat: `parserCreate() * expat: `parserCreate()
<http://hg.python.org/cpython/file/cc27d50bd91a/Modules/expat/xmlparse.c#l724>`_ <http://hg.python.org/cpython/file/cc27d50bd91a/Modules/expat/xmlparse.c#l724>`_
has a per-instance memory handler has a per-instance memory handler
* zlib: `zlib 1.2.8 Manual <http://www.zlib.net/manual.html#Usage>`_,
pass an opaque pointer
* bz2: `bzip2 and libbzip2, version 1.0.5
<http://www.bzip.org/1.0.5/bzip2-manual-1.0.5.html>`_,
pass an opaque pointer
* lzma: `LZMA SDK - How to Use
<http://www.asawicki.info/news_1368_lzma_sdk_-_how_to_use.html>`_,
pass an opaque pointer
* lipmpdec doesn't have this extra *ctx* parameter
Other libraries: Other libraries:
@ -596,6 +606,9 @@ Other libraries:
<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,
Release 2 (9.2)
<http://docs.oracle.com/cd/B10501_01/appdev.920/a96584/oci15re4.htm>`_
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>`_.