Thursday, February 19, 2009

MATLAB: mex out of memory problem using mxCalloc

When writing mex files in ANSI C in Matlab, sometimes there is problem with memory leaks in mex files that eventually causes Out of memory error. One reason for this problem is allocating memory in mex files using e.g. malloc or calloc functions, rather than using Matlab's equivalents e.g. mxMalloc or mxCalloc. The advantage of Matlab's memory allocation functions is that, in theory, Matlab automatically frees allocated dynamic memory when the mex function finishes. Therefore, we do not loose memory. However, when malloc or calloc are used we must deallocate memory ourselves. Matlab provides mxFree function, but we do not need to use it.

Recently I had Out of memory problems with one of my mex files. It took me a while to find the source of it. It was difficult because I did not know why I'm losing memory, even though I was only using mxMalloc to allocate memory, and Matlabs automatically frees all allocated memory. Finally, I found what was the problem. The problem was that memory allocated using mxMalloc is not always freed. To be specific, the problem was with the way I return matrices from mex to Matlab. I was doing this using mxCalloc. In fact there are two ways of returning matrices to Matlab. Method 1 which is based on mxCalloc (in my case) and the second (Method 2) not using any memory allocation. The first method results in memory leaks, although mxCalloc is used, the second method does not have this problem. ANSI C code snippets with these methods://return matrix_a using Method 1 (wrong!)
plhs[0] = mxCreateDoubleMatrix(mrows,ncols, mxREAL);
mxSetPr(plhs[0],makeVectorFromMatrix(matrix_a,mrows,ncols));
or//return matrix_a using method 2 (good!)
double *out_matrix_a;
plhs[0] = mxCreateDoubleMatrix(mrows,ncols, mxREAL);
out_matrix_a = mxGetPr(plhs[0]);
makeVectorFromMatrix2( out_matrix_a, matrix_a,mrows,ncols);
where functions makeVectorFromMatrix and makeVectorFromMatrix2 are:double* makeVectorFromMatrix(double **inData, int mrows, int ncols) {
/*Makes output Vector for METHOD 1*/
int i,j,count=0;

double *out= (double*) mxMalloc((mrows+1)*(ncols+1)*sizeof(double));
for (j=0;j<ncols;j++) {
for (i=0;i<mrows;i++) {

*(out+count)= inData[i][j];
count++;

}
}
return out;
}


void makeVectorFromMatrix2(double *outData, double **inData, int mrows, int ncols) {
/*Makes output Vector for METHOD 2*/
int i,j,count=0;
for (j=0;j<ncols;j++) {
for (i=0;i<mrows;i++) {

*(outData+count)= inData[i][j];
count++;

}
}
}
Full codes of Matlab script and ANSI C mex function for testing memory leaks with these two methods of returning variables to Matlab is attached. The mex function mymexfunction.c creates two 2D arrays, and takes third array as anar argument passed from Matlab. After some processing (multiplying elements of these matrices by 2) the results are returned to Matlab. Executing attached mxCallocTest with argument 1, return matrices by mex function (mymexfunction) using Method 1 (i.e. wrong method) and with argument 2 with method 2 (good method). mxCallocTest.m runs in a long loop executing mymexfunction. When method 1 is used to return variables to matlab, it soon results in Out of Memory error. The second method does not have this problem. An example of results obtained using mxCallocTest.m with argument 1:
>> mxCallocTest(1)
10

20

MATLAB(13826,0x603d000) malloc: *** vm_allocate(size=32034816) failed (error code=3)
MATLAB(13826,0x603d000) malloc: *** error: can't allocate region
MATLAB(13826,0x603d000) malloc: *** set a breakpoint in szone_error to debug
??? Out of memory. Type HELP MEMORY for your options.

Error in ==> mxCallocTest at 24
[matrix_a,matrix_b,matrix_c]= mymexfunction(mrows,ncols,METHOD,c);
The same script but using second method (mxCallocTest(2)) works fine, without memory problems.

The attached scripts also show one, useful way of passing matrices into mex functions, mapping them into 2D arrays, and returning 2D arrays to Matlab as matrices.

Download

Matlab script and ANSI C mex function are here. The files were tested on Intel Mac X 10.4 with Matlab 7.4 and Solaris 9 (UltraSPARC Sun server) with Matlab 7.0.

No comments:

Post a Comment