Memory management problem in mexFunction
I am reading from a binary data file which is written by calling the following lines in m matlab file:
disp (sprintf ('template =% d', fwrite (fid, template_1d, 'uint8')));
AFAIK, uint8 is the same size as BYTE, unsigned char and unsigned short types. So I wrote the following code in a file reader method in C ++ class created in a mexfunction called Matlab:
template1D = (unsigned short *) malloc (Nimgs * sizeof (unsigned short));
printf ("template1D =% d \ n", fread (template1D, sizeof (unsigned short), Nimgs, dfile));
and in the following way how I freed this member variable in the class destructor helper function:
free ((void *) template1D);
In the main mexfunction, when I did not instantiate a class object to persist in memory after the mex function completes, by calling the mexMakeMemoryPersistent () function, template1D gets the correct cleanup without any segmentation error messages from Matlab. However, if I made an instance of the class to be stored in memory like this:
if (! dasani)
{
dasani = new NeedleUSsim;
mexMakeMemoryPersistent ((void *) dasani);
mexAtExit (ExitFcn);
}
with ExitFcn:
void ExitFcn ()
{
delete dasani;
}
then when i am on the line free ((void *) template1D) ;, Matlab tells me a segmentation error message. I have checked the memory sizes and they seem to be consistent. For malloc / calloc / free functions, I use Matlab mxMalloc / mxCalloc / mxFree functions when I execute C ++ project as Matlab mex function.
Based on this description, what further suggestions do you have for me to address this issue and ensure that this does not happen in the future (or at least know how to deal with similar issues like this in the future)?
Thanks in advance.
---------------------------- additions ------------------ --- ---------------------------------
The next block of code basically shows the jists of my mex file. A Mex file is basically an executable file that runs in Matlab and is compiled from C / C ++ code with some Matlab headers.
void ExitFcn ()
{
delete dasani;
}
void mexFunction (int nlhs, mxArray * plhs [], int nrhs, const mxArray * prhs [])
{
needle_info pin;
// check number of i / o if they are correct
if (nrhs! = NUMIN)
{
mexErrMsgTxt ("Invalid number of input arguments");
}
else if (nlhs! = NUMOUT)
{
mexErrMsgTxt ("Invalid number of output arguments");
}
// check if the input is noncomplex
if (mxIsComplex (NEEDLE))
{
mexErrMsgTxt ("Input must be a noncomplex scalar integer.");
}
// check if the dimensions of the needle information is valid
int needlerows, needlecols;
needlerows = mxGetM (NEEDLE);
needlecols = mxGetN (NEEDLE);
if (needlerows < 1 || needlecols < 6)
{
mexErrMsgTxt ("Needle information dimensions are invalid");
}
float * needlePoint, * yPoint;
// retrieving current needle information
// order of the variables are always as follows:
// r, theta, l, rho, alpha, beta
needlePoint = (float *) mxGetData (NEEDLE);
pin.r = needlePoint [0];
pin.theta = needlePoint [1];
pin.l = needlePoint [2];
pin.rho = needlePoint [3];
pin.alpha = needlePoint [4];
pin.beta = needlePoint [5];
//// read the file inputs
** // if (! dasani)
// {
// dasani = new NeedleUSsim;
// mexMakeMemoryPersistent ((void *) dasani);
// mexAtExit (ExitFcn);
//}
dasani = new NeedleUSsim;
delete dasani; **
// sending an useless output for now (get rid of this if not conceptually needed
plhs [0] = mxCreateNumericMatrix (1,1, mxSINGLE_CLASS, mxREAL);
yPoint = (float *) mxGetData (plhs [0]);
* yPoint = 1;
}
This code is run after build / compilation if the user calls "mexfunction" anywhere from the command line or m script file. This snippet enclosed in "**" (when I was trying to display a snippet) is the problem I'm looking at. From a second look at the snippet, I can allocate memory for the dasani pointer in another memory from Matlab memory (since there is memory scoped only by the C ++ mex function, and another memory space with Matlab visible scope). Otherwise, I don't know why Matlab is complaining about this issue.
a source to share
In addition to the fact that dasani is a constant pointer, I also need to make its member variables with the memory allocated by mxMalloc / mxCalloc as well, for example:
if (! dasani)
{
dasani = new NeedleUSsim;
mexMakeMemoryPersistent ((void *) dasani-> tplL);
mexMakeMemoryPersistent ((void *) dasani-> tplR);
mexMakeMemoryPersistent ((void *) dasani-> tplRho_deg);
mexMakeMemoryPersistent ((void *) dasani-> tplAlpha_deg);
mexMakeMemoryPersistent ((void *) dasani-> tplBeta_deg);
mexMakeMemoryPersistent ((void *) dasani-> hashTb);
mexMakeMemoryPersistent ((void *) dasani-> template1D);
mexAtExit (ExitFcn);
}
With a destructor as shown:
void NeedleUSsim :: Deallocate ()
{
free ((void *) tplR); free ((void *) tplL);
free ((void *) tplRho_deg); free ((void *) tplAlpha_deg);
free ((void *) tplBeta_deg);
free ((void *) hashTb);
free ((void *) template1D);
}
a source to share
The MEX API supports C as well as C ++. Since C has no try / catch or destructors, there is no way for the C MEX function to clean up memory directly on error. Therefore, MATLAB keeps track of the results of the memory allocation routines (mxMalloc, mxCalloc, mxRealloc, mxFree, and all mxCreate * functions that return mxArrays) in an internal list. If an error occurs while executing a MEX function (either by calling mexErrMsgIdAndTxt directly, or by using something like mexEvalString to call these MATLAB codes), MATLAB will automatically free any mx-based allocated memory. But also, when the MEX function terminates normally, MATLAB will also free any mx-based memory allocated by the MEX function. Until the days of destructors, this was a convenience for MEX authors, although in today's C ++ world it can get really annoying.
Sometimes, as with this question, you don't want MATLAB to automatically free memory. In this case, you should use mexMakeMemoryPersistent or mexMakeArrayPersistent for mxArrays.
You only need to pass a pointer to mexMakeMemoryPersistent if it was originally allocated by mxMalloc, mxCalloc, or mxRealloc. So this code
dasani = new NeedleUSsim;
mexMakeMemoryPersistent((void*) dasani);
bad with capital "B" unless you overload NeedleUSsim :: operator new () to use mxMalloc, which I would not recommend. But if the dasani fields are allocated by mxMalloc et al., Then you will want to pass them to mexMakeMemoryPersistent. I would recommend doing something like this in NeedleUSsim's constructor, if at all possible, so that it sits next to the mxMalloc call.
a source to share
It seems that it is mexMakeMemoryPersistent () that is causing all these problems. I think you should use it to indicate that Matlab does not delete memory after it completes. But why does Matlab have to delete the dasani pointer? How is this pointer provided in Matlab and what is Matlab for?
a source to share