mexFunction中的内存管理问题

时间:2009-05-25 18:44:08

标签: c++ matlab

我正在读取二进制数据文件,该文件是通过在Matlab m文件中调用以下行来编写的:

disp(sprintf('template = %d', fwrite(fid, template_1d, 'uint8')));

AFAIK,uint8的大小与BYTE,unsigned char和unsigned short相同。因此,我在Matlab调用的mex函数中实例化的C ++类中的文件读取方法中编写了以下代码:

template1D = (unsigned short*) malloc(Nimgs*sizeof(unsigned short));
printf("template1D = %d\n", fread(template1D, sizeof(unsigned short), Nimgs, dfile));

以下是我在类析构函数的辅助函数中释放此成员变量的方法:

free((void*) template1D);

在主mex函数中,当mex函数通过调用mexMakeMemoryPersistent()函数完成后没有实例化类对象在内存中持久化时,template1D被正确清除而没有来自Matlab的分段错误消息。但是,如果我确实将类实例化为在内存中保留,如下所示:

if (!dasani)
{
    dasani = new NeedleUSsim;
    mexMakeMemoryPersistent((void*) dasani);
    mexAtExit(ExitFcn);
}

使用ExitFcn:

void ExitFcn()
{
    delete dasani;
}

然后当我在free((void *)template1D);时,Matlab给我一个关于分段错误的错误消息。我检查了内存大小,它们似乎是一致的。对于malloc / calloc / free函数,当我将C ++项目作为Matlab mex函数执行时,我正在使用Matlab的mxMalloc / mxCalloc / mxFree函数。

根据这个描述,您将有什么进一步的建议来解决这个问题,并确保将来不会发生这种情况(或者至少知道如何在将来处理类似的问题)?

提前致谢。

----------------------------附加------------------ ------------------------------------

以下代码块基本上显示了我的mex文件的数据。 mex文件基本上是一个可执行文件,在Matlab中运行,并使用一些Matlab头文件从C / C ++代码编译。

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's 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;
}

如果用户在命令行或m-file脚本的任何地方调用“mexfunction”,则此代码将在构建/编译后运行。由“**”包围的片段(当我试图加粗片段时)是我正在看的问题。从第二次看片段开始,我可能会在与Matlab内存不同的内存中为dasani指针分配内存(因为内存的范围仅限于C ++ mex函数,另一个内存空间的范围可见Matlab程序)。否则,我不确定为什么Matlab会抱怨这个问题。

3 个答案:

答案 0 :(得分:4)

MEX API支持C和C ++。因为C没有try / catch或析构函数,所以C MEX函数无法在发生错误时直接清理内存。因此,MATLAB在内部列表中跟踪内存分配例程(mxMalloc,mxCalloc,mxRealloc,mxFree和所有返回mxArrays的mxCreate *函数)的结果。如果在执行MEX函数期间发生错误(通过直接调用mexErrMsgIdAndTxt,或者使用类似mexEvalString的函数调用错误的MATLAB代码),则MATLAB将自动释放任何基于mx的已分配内存。但是,当MEX函数正常终止时,MATLAB将会 还释放MEX功能分配的任何基于mx的内存。在析构函数出现之前,这对于MEX作者来说是一种便利,尽管在现代C ++世界中它可能会变得非常烦人。

有时候,就像这个问题一样,你不希望MATLAB自动释放内存。在这种情况下,您必须为mxArrays使用mexMakeMemoryPersistent或mexMakeArrayPersistent。

如果最初使用mxMalloc,mxCalloc或mxRealloc分配,则应该只传递指向mexMakeMemoryPersistent的指针。所以这段代码

dasani = new NeedleUSsim;
mexMakeMemoryPersistent((void*) dasani);

对于大写'B'是不好的,除非你已经重载了NeedleUSsim :: operator new()来使用mxMalloc,我不建议这样做。但是如果使用mxMalloc等分配了dasani的字段,那么 希望将这些字段传递给mexMakeMemoryPersistent。如果可能的话,我建议在NeedleUSsim构造函数中做类似的事情,使其保持在mxMalloc调用附近。

答案 1 :(得分:1)

感觉好像是 mexMakeMemoryPersistent()导致所有这些麻烦。我想你必须用它来指示matlab一旦完成就不要删除内存。但为什么matlab会删除dasani指针?如何将该指针提供给matlab以及matlab需要它做什么?

答案 2 :(得分:0)

除了使dasani成为持久指针之外,我还需要使用mxMalloc / mxCalloc分配的内存使其成员变量也持久化,例如:

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);
}

使用如下所示的析构函数:

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);
}