Skip to content

Commit b18618d

Browse files
committed
Vladimir Marangozov's long-awaited malloc restructuring.
For more comments, read the patches@python.org archives. For documentation read the comments in mymalloc.h and objimpl.h. (This is not exactly what Vladimir posted to the patches list; I've made a few changes, and Vladimir sent me a fix in private email for a problem that only occurs in debug mode. I'm also holding back on his change to main.c, which seems unnecessary to me.)
1 parent 2808b74 commit b18618d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+641
-390
lines changed

Include/mymalloc.h

Lines changed: 107 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ PERFORMANCE OF THIS SOFTWARE.
5757
#include <stdlib.h>
5858
#endif
5959

60+
#include "myproto.h"
61+
6062
#ifdef __cplusplus
6163
/* Move this down here since some C++ #include's don't like to be included
6264
inside an extern "C" */
@@ -67,12 +69,8 @@ extern "C" {
6769
#pragma lib_export on
6870
#endif
6971

70-
/* The following should never be necessary */
71-
#ifdef NEED_TO_DECLARE_MALLOC_AND_FRIEND
72-
extern ANY *malloc Py_PROTO((size_t));
73-
extern ANY *calloc Py_PROTO((size_t, size_t));
74-
extern ANY *realloc Py_PROTO((ANY *, size_t));
75-
extern void free Py_PROTO((ANY *)); /* XXX sometimes int on Unix old systems */
72+
#ifndef DL_IMPORT /* declarations for DLL import */
73+
#define DL_IMPORT(RTYPE) RTYPE
7674
#endif
7775

7876
#ifndef NULL
@@ -87,34 +85,117 @@ extern void free Py_PROTO((ANY *)); /* XXX sometimes int on Unix old systems */
8785
#define _PyMem_EXTRA 0
8886
#endif
8987

90-
#define PyMem_NEW(type, n) \
91-
( (type *) malloc(_PyMem_EXTRA + (n) * sizeof(type)) )
92-
#define PyMem_RESIZE(p, type, n) \
93-
if ((p) == NULL) \
94-
(p) = (type *) malloc(_PyMem_EXTRA + (n) * sizeof(type)); \
95-
else \
96-
(p) = (type *) realloc((ANY *)(p), \
97-
_PyMem_EXTRA + (n) * sizeof(type))
98-
#define PyMem_DEL(p) free((ANY *)p)
99-
#define PyMem_XDEL(p) if ((p) == NULL) ; else PyMem_DEL(p)
88+
/*
89+
* Core memory allocator
90+
* =====================
91+
*/
10092

93+
/* To make sure the interpreter is user-malloc friendly, all memory
94+
APIs are implemented on top of this one.
10195
102-
/* Two sets of function wrappers around malloc and friends; useful if
103-
you need to be sure that you are using the same memory allocator as
104-
Python. Note that the wrappers make sure that allocating 0 bytes
105-
returns a non-NULL pointer, even if the underlying malloc doesn't.
106-
The Python interpreter continues to use PyMem_NEW etc. */
96+
The PyCore_* macros can be defined to make the interpreter use a
97+
custom allocator. Note that they are for internal use only. Both
98+
the core and extension modules should use the PyMem_* API. */
99+
100+
#ifndef PyCore_MALLOC_FUNC
101+
#undef PyCore_REALLOC_FUNC
102+
#undef PyCore_FREE_FUNC
103+
#define PyCore_MALLOC_FUNC malloc
104+
#define PyCore_REALLOC_FUNC realloc
105+
#define PyCore_FREE_FUNC free
106+
#endif
107+
108+
#ifndef PyCore_MALLOC_PROTO
109+
#undef PyCore_REALLOC_PROTO
110+
#undef PyCore_FREE_PROTO
111+
#define PyCore_MALLOC_PROTO Py_PROTO((size_t))
112+
#define PyCore_REALLOC_PROTO Py_PROTO((ANY *, size_t))
113+
#define PyCore_FREE_PROTO Py_PROTO((ANY *))
114+
#endif
115+
116+
#ifdef NEED_TO_DECLARE_MALLOC_AND_FRIEND
117+
extern ANY *PyCore_MALLOC_FUNC PyCore_MALLOC_PROTO;
118+
extern ANY *PyCore_REALLOC_FUNC PyCore_REALLOC_PROTO;
119+
extern void PyCore_FREE_FUNC PyCore_FREE_PROTO;
120+
#endif
121+
122+
#ifndef PyCore_MALLOC
123+
#undef PyCore_REALLOC
124+
#undef PyCore_FREE
125+
#define PyCore_MALLOC(n) PyCore_MALLOC_FUNC(n)
126+
#define PyCore_REALLOC(p, n) PyCore_REALLOC_FUNC((p), (n))
127+
#define PyCore_FREE(p) PyCore_FREE_FUNC(p)
128+
#endif
107129

108-
/* These wrappers around malloc call PyErr_NoMemory() on failure */
109-
extern DL_IMPORT(ANY *) Py_Malloc Py_PROTO((size_t));
110-
extern DL_IMPORT(ANY *) Py_Realloc Py_PROTO((ANY *, size_t));
111-
extern DL_IMPORT(void) Py_Free Py_PROTO((ANY *));
130+
/* BEWARE:
112131
113-
/* These wrappers around malloc *don't* call anything on failure */
132+
Each interface exports both functions and macros. Extension modules
133+
should normally use the functions for ensuring binary compatibility
134+
of the user's code across Python versions. Subsequently, if the
135+
Python runtime switches to its own malloc (different from standard
136+
malloc), no recompilation is required for the extensions.
137+
138+
The macro versions trade compatibility for speed. They can be used
139+
whenever there is a performance problem, but their use implies
140+
recompilation of the code for each new Python release. The Python
141+
core uses the macros because it *is* compiled on every upgrade.
142+
This might not be the case with 3rd party extensions in a custom
143+
setup (for example, a customer does not always have access to the
144+
source of 3rd party deliverables). You have been warned! */
145+
146+
/*
147+
* Raw memory interface
148+
* ====================
149+
*/
150+
151+
/* Functions */
152+
153+
/* Function wrappers around PyCore_MALLOC and friends; useful if you
154+
need to be sure that you are using the same memory allocator as
155+
Python. Note that the wrappers make sure that allocating 0 bytes
156+
returns a non-NULL pointer, even if the underlying malloc
157+
doesn't. Returned pointers must be checked for NULL explicitly.
158+
No action is performed on failure. */
114159
extern DL_IMPORT(ANY *) PyMem_Malloc Py_PROTO((size_t));
115160
extern DL_IMPORT(ANY *) PyMem_Realloc Py_PROTO((ANY *, size_t));
116161
extern DL_IMPORT(void) PyMem_Free Py_PROTO((ANY *));
117162

163+
/* Starting from Python 1.6, the wrappers Py_{Malloc,Realloc,Free} are
164+
no longer supported. They used to call PyErr_NoMemory() on failure. */
165+
166+
/* Macros */
167+
#define PyMem_MALLOC(n) PyCore_MALLOC(n)
168+
#define PyMem_REALLOC(p, n) PyCore_REALLOC((ANY *)(p), (n))
169+
#define PyMem_FREE(p) PyCore_FREE((ANY *)(p))
170+
171+
/*
172+
* Type-oriented memory interface
173+
* ==============================
174+
*/
175+
176+
/* Functions */
177+
#define PyMem_New(type, n) \
178+
( (type *) PyMem_Malloc((n) * sizeof(type)) )
179+
#define PyMem_Resize(p, type, n) \
180+
( (p) = (type *) PyMem_Realloc((n) * sizeof(type)) )
181+
#define PyMem_Del(p) PyMem_Free(p)
182+
183+
/* Macros */
184+
#define PyMem_NEW(type, n) \
185+
( (type *) PyMem_MALLOC(_PyMem_EXTRA + (n) * sizeof(type)) )
186+
#define PyMem_RESIZE(p, type, n) \
187+
if ((p) == NULL) \
188+
(p) = (type *)(PyMem_MALLOC( \
189+
_PyMem_EXTRA + (n) * sizeof(type))); \
190+
else \
191+
(p) = (type *)(PyMem_REALLOC((p), \
192+
_PyMem_EXTRA + (n) * sizeof(type)))
193+
#define PyMem_DEL(p) PyMem_FREE(p)
194+
195+
/* PyMem_XDEL is deprecated. To avoid the call when p is NULL,
196+
it is recommended to write the test explicitly in the code.
197+
Note that according to ANSI C, free(NULL) has no effect. */
198+
118199
#ifdef __cplusplus
119200
}
120201
#endif

Include/objimpl.h

Lines changed: 187 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -35,42 +35,204 @@ PERFORMANCE OF THIS SOFTWARE.
3535
3636
******************************************************************/
3737

38+
#include "mymalloc.h"
39+
3840
/*
39-
Additional macros for modules that implement new object types.
41+
Functions and macros for modules that implement new object types.
4042
You must first include "object.h".
4143
42-
PyObject_NEW(type, typeobj) allocates memory for a new object of the given
43-
type; here 'type' must be the C structure type used to represent the
44-
object and 'typeobj' the address of the corresponding type object.
45-
Reference count and type pointer are filled in; the rest of the bytes of
46-
the object are *undefined*! The resulting expression type is 'type *'.
47-
The size of the object is actually determined by the tp_basicsize field
48-
of the type object.
44+
- PyObject_New(type, typeobj) allocates memory for a new object of
45+
the given type; here 'type' must be the C structure type used to
46+
represent the object and 'typeobj' the address of the corresponding
47+
type object. Reference count and type pointer are filled in; the
48+
rest of the bytes of the object are *undefined*! The resulting
49+
expression type is 'type *'. The size of the object is actually
50+
determined by the tp_basicsize field of the type object.
51+
52+
- PyObject_NewVar(type, typeobj, n) is similar but allocates a
53+
variable-size object with n extra items. The size is computed as
54+
tp_basicsize plus n * tp_itemsize. This fills in the ob_size field
55+
as well.
56+
57+
- PyObject_Del(op) releases the memory allocated for an object.
58+
59+
- PyObject_Init(op, typeobj) and PyObject_InitVar(op, typeobj, n) are
60+
similar to PyObject_{New, NewVar} except that they don't allocate
61+
the memory needed for an object. Instead of the 'type' parameter,
62+
they accept the pointer of a new object (allocated by an arbitrary
63+
allocator) and initialize its object header fields.
64+
65+
Note that objects created with PyObject_{New, NewVar} are allocated
66+
within the Python heap by an object allocator, the latter being
67+
implemented (by default) on top of the Python raw memory
68+
allocator. This ensures that Python keeps control on the user's
69+
objects regarding their memory management; for instance, they may be
70+
subject to automatic garbage collection.
71+
72+
In case a specific form of memory management is needed, implying that
73+
the objects would not reside in the Python heap (for example standard
74+
malloc heap(s) are mandatory, use of shared memory, C++ local storage
75+
or operator new), you must first allocate the object with your custom
76+
allocator, then pass its pointer to PyObject_{Init, InitVar} for
77+
filling in its Python-specific fields: reference count, type pointer,
78+
possibly others. You should be aware that Python has very limited
79+
control over these objects because they don't cooperate with the
80+
Python memory manager. Such objects may not be eligible for automatic
81+
garbage collection and you have to make sure that they are released
82+
accordingly whenever their destructor gets called (cf. the specific
83+
form of memory management you're using).
84+
85+
Unless you have specific memory management requirements, it is
86+
recommended to use PyObject_{New, NewVar, Del}. */
87+
88+
/*
89+
* Core object memory allocator
90+
* ============================
91+
*/
4992

50-
PyObject_NEW_VAR(type, typeobj, n) is similar but allocates a variable-size
51-
object with n extra items. The size is computed as tp_basicsize plus
52-
n * tp_itemsize. This fills in the ob_size field as well.
53-
*/
93+
/* The purpose of the object allocator is to make make the distinction
94+
between "object memory" and the rest within the Python heap.
95+
96+
Object memory is the one allocated by PyObject_{New, NewVar}, i.e.
97+
the one that holds the object's representation defined by its C
98+
type structure, *excluding* any object-specific memory buffers that
99+
might be referenced by the structure (for type structures that have
100+
pointer fields). By default, the object memory allocator is
101+
implemented on top of the raw memory allocator.
54102
55-
#ifndef MS_COREDLL
103+
The PyCore_* macros can be defined to make the interpreter use a
104+
custom object memory allocator. They are reserved for internal
105+
memory management purposes exclusively. Both the core and extension
106+
modules should use the PyObject_* API. */
107+
108+
#ifndef PyCore_OBJECT_MALLOC_FUNC
109+
#undef PyCore_OBJECT_REALLOC_FUNC
110+
#undef PyCore_OBJECT_FREE_FUNC
111+
#define PyCore_OBJECT_MALLOC_FUNC PyCore_MALLOC_FUNC
112+
#define PyCore_OBJECT_REALLOC_FUNC PyCore_REALLOC_FUNC
113+
#define PyCore_OBJECT_FREE_FUNC PyCore_FREE_FUNC
114+
#endif
115+
116+
#ifndef PyCore_OBJECT_MALLOC_PROTO
117+
#undef PyCore_OBJECT_REALLOC_PROTO
118+
#undef PyCore_OBJECT_FREE_PROTO
119+
#define PyCore_OBJECT_MALLOC_PROTO PyCore_MALLOC_PROTO
120+
#define PyCore_OBJECT_REALLOC_PROTO PyCore_REALLOC_PROTO
121+
#define PyCore_OBJECT_FREE_PROTO PyCore_FREE_PROTO
122+
#endif
123+
124+
#ifdef NEED_TO_DECLARE_OBJECT_MALLOC_AND_FRIEND
125+
extern ANY *PyCore_OBJECT_MALLOC_FUNC PyCore_OBJECT_MALLOC_PROTO;
126+
extern ANY *PyCore_OBJECT_REALLOC_FUNC PyCore_OBJECT_REALLOC_PROTO;
127+
extern void PyCore_OBJECT_FREE_FUNC PyCore_OBJECT_FREE_PROTO;
128+
#endif
129+
130+
#ifndef PyCore_OBJECT_MALLOC
131+
#undef PyCore_OBJECT_REALLOC
132+
#undef PyCore_OBJECT_FREE
133+
#define PyCore_OBJECT_MALLOC(n) PyCore_OBJECT_MALLOC_FUNC(n)
134+
#define PyCore_OBJECT_REALLOC(p, n) PyCore_OBJECT_REALLOC_FUNC((p), (n))
135+
#define PyCore_OBJECT_FREE(p) PyCore_OBJECT_FREE_FUNC(p)
136+
#endif
137+
138+
/*
139+
* Raw object memory interface
140+
* ===========================
141+
*/
142+
143+
/* The use of this API should be avoided, unless a builtin object
144+
constructor inlines PyObject_{New, NewVar}, either because the
145+
latter functions cannot allocate the exact amount of needed memory,
146+
either for speed. This situation is exceptional, but occurs for
147+
some object constructors (PyBuffer_New, PyList_New...). Inlining
148+
PyObject_{New, NewVar} for objects that are supposed to belong to
149+
the Python heap is discouraged. If you really have to, make sure
150+
the object is initialized with PyObject_{Init, InitVar}. Do *not*
151+
inline PyObject_{Init, InitVar} for user-extension types or you
152+
might seriously interfere with Python's memory management. */
153+
154+
/* Functions */
155+
156+
/* Wrappers around PyCore_OBJECT_MALLOC and friends; useful if you
157+
need to be sure that you are using the same object memory allocator
158+
as Python. These wrappers *do not* make sure that allocating 0
159+
bytes returns a non-NULL pointer. Returned pointers must be checked
160+
for NULL explicitly; no action is performed on failure. */
161+
extern DL_IMPORT(ANY *) PyObject_Malloc Py_PROTO((size_t));
162+
extern DL_IMPORT(ANY *) PyObject_Realloc Py_PROTO((ANY *, size_t));
163+
extern DL_IMPORT(void) PyObject_Free Py_PROTO((ANY *));
164+
165+
/* Macros */
166+
#define PyObject_MALLOC(n) PyCore_OBJECT_MALLOC(n)
167+
#define PyObject_REALLOC(op, n) PyCore_OBJECT_REALLOC((ANY *)(op), (n))
168+
#define PyObject_FREE(op) PyCore_OBJECT_FREE((ANY *)(op))
169+
170+
/*
171+
* Generic object allocator interface
172+
* ==================================
173+
*/
174+
175+
/* Functions */
176+
extern DL_IMPORT(PyObject *) PyObject_Init Py_PROTO((PyObject *, PyTypeObject *));
177+
extern DL_IMPORT(PyVarObject *) PyObject_InitVar Py_PROTO((PyVarObject *, PyTypeObject *, int));
56178
extern DL_IMPORT(PyObject *) _PyObject_New Py_PROTO((PyTypeObject *));
57179
extern DL_IMPORT(PyVarObject *) _PyObject_NewVar Py_PROTO((PyTypeObject *, int));
180+
extern DL_IMPORT(void) _PyObject_Del Py_PROTO((PyObject *));
181+
182+
#define PyObject_New(type, typeobj) \
183+
( (type *) _PyObject_New(typeobj) )
184+
#define PyObject_NewVar(type, typeobj, n) \
185+
( (type *) _PyObject_NewVar((typeobj), (n)) )
186+
#define PyObject_Del(op) _PyObject_Del((PyObject *)(op))
187+
188+
/* Macros trading binary compatibility for speed. See also mymalloc.h.
189+
Note that these macros expect non-NULL object pointers.*/
190+
#define PyObject_INIT(op, typeobj) \
191+
( (op)->ob_type = (typeobj), _Py_NewReference((PyObject *)(op)), (op) )
192+
#define PyObject_INIT_VAR(op, typeobj, size) \
193+
( (op)->ob_size = (size), PyObject_INIT((op), (typeobj)) )
194+
195+
#define _PyObject_SIZE(typeobj) ( (typeobj)->tp_basicsize )
196+
#define _PyObject_VAR_SIZE(typeobj, n) \
197+
( (typeobj)->tp_basicsize + (n) * (typeobj)->tp_itemsize )
198+
199+
#define PyObject_NEW(type, typeobj) \
200+
( (type *) PyObject_Init( \
201+
(PyObject *) PyObject_MALLOC( _PyObject_SIZE(typeobj) ), (typeobj)) )
202+
#define PyObject_NEW_VAR(type, typeobj, n) \
203+
( (type *) PyObject_InitVar( \
204+
(PyVarObject *) PyObject_MALLOC( _PyObject_VAR_SIZE((typeobj),(n)) ),\
205+
(typeobj), (n)) )
206+
#define PyObject_DEL(op) PyObject_FREE(op)
207+
208+
/* This example code implements an object constructor with a custom
209+
allocator, where PyObject_New is inlined, and shows the important
210+
distinction between two steps (at least):
211+
1) the actual allocation of the object storage;
212+
2) the initialization of the Python specific fields
213+
in this storage with PyObject_{Init, InitVar}.
214+
215+
PyObject *
216+
YourObject_New(...)
217+
{
218+
PyObject *op;
58219
59-
#define PyObject_NEW(type, typeobj) ((type *) _PyObject_New(typeobj))
60-
#define PyObject_NEW_VAR(type, typeobj, n) ((type *) _PyObject_NewVar(typeobj, n))
220+
op = (PyObject *) Your_Allocator(_PyObject_SIZE(YourTypeStruct));
221+
if (op == NULL)
222+
return PyErr_NoMemory();
61223
62-
#else
63-
/* For an MS-Windows DLL, we change the way an object is created, so that the
64-
extension module's malloc is used, rather than the core DLL malloc, as there is
65-
no guarantee they will use the same heap
66-
*/
67-
extern DL_IMPORT(PyObject *) _PyObject_New Py_PROTO((PyTypeObject *, PyObject *));
68-
extern DL_IMPORT(PyVarObject *) _PyObject_NewVar Py_PROTO((PyTypeObject *, int, PyVarObject *));
224+
op = PyObject_Init(op, &YourTypeStruct);
225+
if (op == NULL)
226+
return NULL;
69227
70-
#define PyObject_NEW(type, typeobj) ((type *) _PyObject_New(typeobj,(PyObject *)malloc((typeobj)->tp_basicsize)))
71-
#define PyObject_NEW_VAR(type, typeobj, n) ((type *) _PyObject_NewVar(typeobj, n, (PyVarObject *)malloc((typeobj)->tp_basicsize + n * (typeobj)->tp_itemsize)))
228+
op->ob_field = value;
229+
...
230+
return op;
231+
}
72232
73-
#endif /* MS_COREDLL */
233+
Note that in C++, the use of the new operator usually implies that
234+
the 1st step is performed automatically for you, so in a C++ class
235+
constructor you would start directly with PyObject_Init/InitVar. */
74236

75237
#ifdef __cplusplus
76238
}

0 commit comments

Comments
 (0)