Memory Allocations¶
Blender features its own memory allocation library, which is a thin wrapper around an underlying allocator. Depending on the platform and type of build, this allocator can be the jemalloc library, the oneTBB allocator, or the default system one.
Its API is defined in
intern/guardedalloc/MEM_guardedalloc.h
.
C++-style Creation - MEM_new
and MEM_delete
¶
The main way to allocate and construct an instance of a type in C++ code
is to use the MEM_new<T>
template function. It will allocate memory for
the given type and call its constructor.
Just like when using the new
operator, parameters for the constructor
can be passed to the MEM_new<T>
function.
Note
Even when creating 'C' data (i.e. using trivial data types), in new C++ code it is recommended to use this API whenever possible. This will save a fair amount of work (and potential issues) if/when said types become non-trivial in the future.
Data allocated and constructed this way must be destructed and freed with
MEM_delete
.
Note
Technically, MEM_delete
is a template (MEM_delete<T>
). However,
compilers should always be able to deduct the correct type from the given
parameter, so it should never be needed to explicitely specify that
template parameter:
new
& delete
Operators¶
Using the new
and delete
operators for Blender data types should
typically be avoided.
However, there are some cases where this is difficult not to use them
(e.g. when using external libraries or the standard containers, like
std::vector
).
In such cases, it is still possible to get default new
/delete
operators
to use the MEM_guardedalloc
allocator, by overloading them in the
affected data types. Structs and classes that need this should use the
MEM_CXX_CLASS_ALLOC_FUNCS
macro in their declaration.
Note that a type using overloaded new
& delete
operators can still also
be created and deleted with MEM_new<T>
and MEM_delete<T>
.
C-style Allocation - MEM_[cm]allocN
& MEM_freeN
¶
In C++ code, when using MEM_new<T>
/MEM_delete<T>
is not possible, the
recommended way to allocate memory for a given struct (without any
construction) is to use the templated version of MEM_callocN<T>
/
MEM_mallocN<T>
(or MEM_calloc_arrayN<T>
/ MEM_malloc_arrayN<T>
for
arrays). This is essentially a template wrapper around calloc
/malloc
,
i.e. it will allocate the requested memory for the given type (and
initialize it to zero for the calloc
ones).
This API is type-safe, in that it ensures that the allocated type matches the returned pointer type. It also does some basic checks at compile time, ensuring that the given type is 'trivial', i.e. that it does not require any constructor call to be valid. This adds a significant amount of safety in a codebase that mixes heavily trivial, C-style data types (also known as POD, Plain Old Data), with non-trivial, C++-style ones.
The main reason to use this allocation-only API in new code is in case the created data needs to be used in some existing code, that manages it with 'C-style' allocation calls.
The historic API (non-templated, type-agnostic MEM_mallocN
, MEM_callocN
,
etc.) should only be used directly in specific cases. In general, when a
specific allocation size value has to be used:
* When allocating a not fully defined type, or some raw buffer of bytes.
* In implementation of some containers (like Vector or Map), when calling
code explicitely needs to allocate memory for a non-trivial C++ struct,
and take care of its construction (e.g. with a placement new
) separately.
* In some Blender historic core code, mimicking C++ type inheritance, e.g.
ID and Modifier creation.
Data allocated these ways (both the templated and 'C-style' versions of the
API) must be freed with MEM_freeN
. This function also does static type
checking regarding triviality of the deleted data type, in C++ code. In
case the type is not fully defined when freeing the data:
* It might be worth reconsidering the API around that type (as it likely means
that it is allocated somewhere, and freed in a completely different part of
the code).
* If such 'unknown data' freeing is really necessary, the pointer must be
explicitly cast to void *
in the call to MEM_freeN
.
Note
Technically, as with MEM_delete
, MEM_freeN
is a template
(MEM_freeN<T>
), but explicitely giving the type parameter to the template
should never be needed.
Note
The C-compatible version of MEM_freeN
, which takes a void *
parameter,
is implemented as a non-templated overload of the function.