Memory erased in mex file

3 ビュー (過去 30 日間)
Pang
Pang 2019 年 9 月 17 日
コメント済み: Pang 2019 年 9 月 23 日
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.

採用された回答

James Tursa
James Tursa 2019 年 9 月 19 日
編集済み: James Tursa 2019 年 9 月 19 日
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 件のコメント
Pang
Pang 2019 年 9 月 23 日
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! :-)

サインインしてコメントする。

その他の回答 (0 件)

カテゴリ

Help Center および File ExchangeWrite C Functions Callable from MATLAB (MEX Files) についてさらに検索

タグ

製品


リリース

R2017a

Community Treasure Hunt

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

Start Hunting!

Translated by