Main Content

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 mxArrays 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.

See Also

|

Related Topics