Memory Management Issues
Overview
Note
The examples in this topic use functions in the interleaved complex API. To
build applications with these functions, call mex
with the
release-specific option -R2018a
.
When a MEX function returns control to MATLAB®, it returns the results of its computations in the output arguments—the
mxArray
s contained in the left-side arguments plhs[]
.
These arrays must have a temporary scope, so do not pass arrays created with the
mexMakeArrayPersistent
function in plhs
. MATLAB destroys any mxArray
created by the MEX function that is not in
plhs
. MATLAB also frees any memory that was allocated in the MEX function using the
mxCalloc
, mxMalloc
, or
mxRealloc
functions.
In general, MathWorks® recommends that MEX functions destroy their own temporary arrays and free their own dynamically allocated memory. It is more efficient to perform this cleanup in the source MEX file than to rely on the automatic mechanism. This approach is consistent with other MATLAB API applications (MAT-file applications, engine applications, and MATLAB Compiler™ generated applications, which do not have any automatic cleanup mechanism.)
However, do not destroy an mxArray
in a source MEX file when it
is:
passed to the MEX file in the right-hand side list
prhs[]
returned in the left side list
plhs[]
returned by
mexGetVariablePtr
used to create a structure
This section describes situations specific to memory management. We recommend that you review code in your source MEX files to avoid using these functions in the following situations. For more information, see Automatic Cleanup of Temporary Arrays in MEX Files and Persistent mxArrays. For guidance on memory issues, see Strategies for Efficient Use of Memory.
Potential memory management problems include:
Improperly Destroying an mxArray
Do not use mxFree
to destroy an
mxArray
.
Example
In the following example, mxFree
does not destroy the
array object. This operation frees the structure header associated with the
array, but MATLAB still operates as if the array object needs to be destroyed. Thus
MATLAB tries to destroy the array object, and in the process, attempts to
free its structure header again:
mxArray *temp = mxCreateDoubleMatrix(1,1,mxREAL); ... mxFree(temp); /* INCORRECT */
Solution
Call mxDestroyArray
instead:
mxDestroyArray(temp); /* CORRECT */
Incorrectly Constructing a Cell or Structure mxArray
Do not call mxSetCell
or mxSetField
variants with prhs[]
as the member array.
Example
In the following example, when the MEX file returns, MATLAB destroys the entire cell array. Since this includes the members of the cell, this implicitly destroys the input arguments of the MEX file. This can cause several strange results, generally having to do with the corruption of the caller workspace, if the right-hand side argument used is a temporary array (for example, a literal or the result of an expression):
myfunction('hello') /* myfunction is the name of your MEX file and your code /* contains the following: */ mxArray *temp = mxCreateCellMatrix(1,1); ... mxSetCell(temp, 0, prhs[0]); /* INCORRECT */
Solution
Make a copy of the right-hand side argument with
mxDuplicateArray
and use that copy as the argument to
mxSetCell
(or mxSetField
variants). For example:
mxSetCell(temp, 0, mxDuplicateArray(prhs[0])); /* CORRECT */
Creating a Temporary mxArray
with Improper Data
Do not call mxDestroyArray
on an mxArray
whose data was not allocated by an API routine.
Example
If you call mxSetDoubles
,
mxSetComplexDoubles
, or any of the typed data access
functions specifying memory that was not allocated by
mxCalloc
, mxMalloc
, or
mxRealloc
as the intended data block (second argument),
then when the MEX file returns, MATLAB attempts to free the pointers to real data and imaginary data (if
any). Thus MATLAB attempts to free memory, in this example, from the program
stack:
mxArray *temp = mxCreateDoubleMatrix(0,0,mxREAL); double data[5] = {1,2,3,4,5}; ... mxSetM(temp,1); mxSetN(temp,5); mxSetDoubles(temp, data); /* INCORRECT */
Solution
Rather than use mxSetDoubles
to set the data pointer,
instead, create the mxArray
with the right size and use
memcpy
to copy the stack data into the buffer returned by
mxGetDoubles
:
mxArray *temp = mxCreateDoubleMatrix(1,5,mxREAL); double data[5] = {1,2,3,4,5}; ... memcpy(mxGetDoubles(temp), data, 5*sizeof(double)); /* CORRECT */
Creating Potential Memory Leaks
Before Version 5.2, if you created an mxArray
using one of the
API creation routines and then you overwrote the pointer to the data using
mxSetDoubles
, MATLAB still freed the original memory. MATLAB no longer frees the memory.
For example:
pr = mxCalloc(5*5, sizeof(double)); ... <load data into pr> plhs[0] = mxCreateDoubleMatrix(5,5,mxREAL); mxSetDoubles(plhs[0], pr); /* INCORRECT */
now leaks 5*5*8 bytes of memory, where 8 bytes is the size of a
double
.
You can avoid that memory leak by changing the code to:
plhs[0] = mxCreateDoubleMatrix(5,5,mxREAL); pr = mxGetDoubles(plhs[0]); ... <load data into pr>
or alternatively:
pr = mxCalloc(5*5, sizeof(double)); ... <load data into pr> plhs[0] = mxCreateDoubleMatrix(5,5,mxREAL); mxFree(mxGetDoubles(plhs[0])); mxSetDoubles(plhs[0], pr);
The first solution is more efficient.
Similar memory leaks can also occur when using mxSetDoubles
,
mxSetComplexDoubles
, mxSetIr
,
mxSetJc
, or any of the numeric typed data access functions.
You can avoid memory leaks by changing the code as described in this section.
Improperly Destroying a Structure
For a structure, you must call mxDestroyArray
only on the
structure, not on the field data arrays. A field in the structure points to the data
in the array used by mxSetField
or
mxSetFieldByNumber
. When
mxDestroyArray
destroys the structure, it attempts to
traverse down through itself and free all other data, including the memory in the
data arrays. If you call mxDestroyArray
on each data array, the
same memory is freed twice which can corrupt memory.
Example
The following example creates three arrays: one structure array
aStruct
and two data arrays, myDataOne
and myDataTwo
. Field name one
contains a
pointer to the data in myDataOne
, and field name
two
contains a pointer to the data in
myDataTwo
.
mxArray *myDataOne; mxArray *myDataTwo; mxArray *aStruct; const char *fields[] = { "one", "two" }; myDataOne = mxCreateDoubleScalar(1.0); myDataTwo = mxCreateDoubleScalar(2.0); aStruct = mxCreateStructMatrix(1,1,2,fields); mxSetField( aStruct, 0, "one", myDataOne ); mxSetField( aStruct, 1, "two", myDataTwo ); mxDestroyArray(myDataOne); mxDestroyArray(myDataTwo); mxDestroyArray(aStruct); /* tries to free myDataOne and myDataTwo */
Solution
The command mxDestroyArray(aStruct)
destroys the data in
all three arrays:
... aStruct = mxCreateStructMatrix(1,1,2,fields); mxSetField( aStruct, 0, "one", myDataOne ); mxSetField( aStruct, 1, "two", myDataTwo ); mxDestroyArray(aStruct);
Destroying Memory in a C++ Class Destructor
Do not use the mxFree
or mxDestroyArray
functions
in a C++ destructor of a class used in a MEX-function. If the MEX-function
throws an error, MATLAB cleans up MEX-file variables, as described
in Automatic Cleanup of Temporary Arrays in MEX Files.
If an error occurs that causes the object to go out of scope, MATLAB calls the C++ destructor. Freeing memory directly in the destructor means both MATLAB and the destructor free the same memory, which can corrupt memory.