Memory erased in mex file

1 vue (au cours des 30 derniers jours)
Pang
Pang le 17 Sep 2019
Commenté : Pang le 23 Sep 2019
Hi, I'm having a really strange issue with the memory when calling a mex funcion. I have two mex functions, one for initialization and one for processing. the first one looks like this:
#include <matrix.h>
#include <mex.h>
#define NCHANNELS 6
#define SAMPLINGRATE 48000
typedef struct myStruct
{
// Configuration.
int _fsamp; // Sample rate.
int _nchan; // Number of channels.
}myStruct;
void init_function(myStruct *C, int nchan, int fsamp)
{
C->_nchan = nchan;
C->_fsamp = fsamp;
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
int samplingrate;
int nchannels;
myStruct **c_ptr;
plhs[0] = mxCreateNumericMatrix(1, 1, mxINT32_CLASS, mxREAL);
c_ptr = (myStruct **) mxGetData(plhs[0]);
// default values
samplingrate = SAMPLINGRATE;
nchannels = NCHANNELS;
myStruct *c = (myStruct *) mxMalloc(sizeof(myStruct));
//init_function(c, nchannels, samplingrate);
c->_nchan = nchannels;
c->_fsamp = samplingrate;
*c_ptr = c;
mexPrintf("Initialized for %i channels and %i sampling rate.\n",(*c_ptr)->_nchan,(*c_ptr)->_fsamp);
}
and the processing like:
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
int ind, nframe, nchannels;
float *ptr_in[NCHANNELS], *ptr_out[NCHANNELS];
const mwSize outsize[] = {FRAMESIZE, NCHANNELS};
myStruct **c_ptr;
const mxArray *mxInput = prhs[1];
const mxArray *mxPointer = prhs[0];
// Get actual array size
nframe = mxGetM(mxInput); // number of samples per block
nchannels = mxGetN(mxInput);
// create output array
plhs[0] = mxDuplicateArray(mxInput);
// return the pointer
plhs[1] = mxDuplicateArray(mxPointer);
// call processing function
c_ptr = (myStruct **) mxGetData(mxPointer);
mexPrintf("Channels %d, sampling freq. %d\n", (*c_ptr)->_nchan, (*c_ptr)->_fsamp);
if ((*c_ptr)->_nchan != (int) nchannels)
{
mexPrintf("Input signal should have %d channels and sampling freq %d.\n",(*c_ptr)->_nchan, (*c_ptr)->_fsamp);
//mexPrintf("Pointer2 %lld\n", *c_ptr);
return;
}
}
in this simplified version i'm just returning the pointer and the input matrix for the sake of simplicity (the actual code i'm modifiying the input). Let's say i compiled the first mexfunciton as myFunction_init.c and the second as myFunction.c. Still, with this simplified code I get a very strange behaviour when I run this:
data_in = single(randn(512,6));
p = 1;
while p
p = myFunction_init;
for n = 1:10
[data_out,p] = myFunction(p, data_in);
end
end
the first iteration of the while loop gives this:
Initialized for 6 channels and 48000 sampling rate.
Channels 0, sampling freq. 1991125456
Input signal should have 0 channels and sampling freq 1991125456.
which is obviously garbage. The second iteration would return correct data, i.e.:
Initialized for 6 channels and 48000 sampling rate.
Channels 6, sampling freq. 48000
This behaviour happens usually at the first iteration and randomly during the while loop. I still can't figure out what it is happening here, so any help would be really appreciated.

Réponse acceptée

James Tursa
James Tursa le 19 Sep 2019
Modifié(e) : James Tursa le 19 Sep 2019
I would highly advise combining your multiple mex routines into one mex routine that you call with a directive (e.g., a string) indicating the action you want the mex routine to take (e.g., 'init', 'process', 'clear', etc.). That way all of the memory allocation and usage is within one mex routine and can be more easily managed to avoid memory access issues and memory leaks. That being said, here are some problems I observe with your code:
Invalid memory:
myStruct **c_ptr;
plhs[0] = mxCreateNumericMatrix(1, 1, mxINT32_CLASS, mxREAL); <-- create the output variable
c_ptr = (myStruct **) mxGetData(plhs[0]); <-- get a pointer to the plhs[0] data area
:
myStruct *c = (myStruct *) mxMalloc(sizeof(myStruct)); <-- memory is on garbage collection list
:
*c_ptr = c; <-- pointer to memory placed into plhs[0], but pointer still on garbage collection list
As soon as your mex function returns to the caller, the memory behind the c pointer is free'd by the automatic garbage collection and is invalid. Any further access of this memory downstream, which you do, will either give garbage results or crash MATLAB. You could solve this by the following:
mexMakeMemoryPersistent(c); <-- ensure c memory is not on garbage collection list
But then you risk a memory leak because you currently have no code to free c and you are not remembering the c pointer inside your mex function. So you would need to add a mexAtExit function to do this. You might also want to have a directive (e.g., 'clear') that does this via user command.
What you really need to do is remember the c pointer inside your mex function (e.g., as a top level global variable) so that you can free it when necessary (mex routine is cleared or user uses the 'clear' command). Top level global variables retain their values between mex calls as long as you don't clear the mex function from memory.
This becomes very tricky if you have the pointer value inside a MATLAB variable in the workspace. If you pass that pointer value into the mex routine, the mex routine would need to be able to check its validity before using it (e.g., compare it to the top level global variable value) or again you risk a crash, etc.
Also, you are using an mxINT32_CLASS variable to hold a pointer value ... this will not work if you are running a 64-bit version of MATLAB where pointers are 64-bits.
Another option would be to pass the structure itself back in the plhs[0] variable and let MATLAB handle this memory just like any other normal variable. This avoids remembering the pointer and memory deallocation issues entirely. This would only make sense if the struct contained only data and not pointers to resources. E.g., a rough outline:
myStruct *c = (myStruct *) mxMalloc(sizeof(myStruct));
:
plhs[0] = mxCreateNumericMatrix(0, 0, mxUINT8_CLASS, mxREAL);
mxSetData(plhs[0],c); <-- c no longer on garbage collection list
mxSetM(plhs[0],1);
mxSetN(plhs[0],sizeof(myStruct));
  1 commentaire
Pang
Pang le 23 Sep 2019
the problem was indeed that the memory behing c was cleared after the call of the function and therefore giving garbage out randomly. I use now mexMakeMemoryPersistent( c) with mexAtExit to clear c and it's now working properly and without crashing
The latest suggestion of passing the structure to the left hand side wouldn't work in my case, since in the actual code this structure also contains some pointers, which are then modified inside another function. So that wouldn't do.
Anyway, it's now working. Thanks a lot! :-)

Connectez-vous pour commenter.

Plus de réponses (0)

Catégories

En savoir plus sur Write C Functions Callable from MATLAB (MEX Files) dans Help Center et File Exchange

Tags

Produits


Version

R2017a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by