проблема управления памятью в mexFunction - PullRequest
1 голос
/ 25 мая 2009

Я читаю из файла двоичных данных, который записывается путем вызова следующих строк в m-файле Matlab:

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

AFAIK, uint8 имеет тот же размер, что и типы BYTE, unsigned char и unsigned short. Следовательно, я написал следующий код в методе чтения файлов в классе C ++, созданном в функции mexfunction, вызываемой Matlab:

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

и вот как я освободил эту переменную-член в вспомогательной функции деструктора класса:

free((void*) template1D);

В основной mexfunction, когда я не создавал экземпляр объекта класса для сохранения в памяти после завершения 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 я использую функции mxMalloc / mxCalloc / mxFree в Matlab, когда выполняю проект C ++ как mex-функцию Matlab.

Исходя из этого описания, какие дополнительные предложения вы бы предложили мне для решения этой проблемы и обеспечения того, чтобы этого не произошло в будущем (или, по крайней мере, знаете, как решать подобные проблемы в будущем)?

Заранее спасибо.

---------------------------- дополнения ------------------ ------------------------------------

Следующий блок кода в основном показывает списки моего mex-файла. Mex-файл - это исполняемый файл, который запускается в Matlab и компилируется из кода C / C ++ с некоторыми заголовками Matlab.

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

Этот код будет запускаться после сборки / компиляции, если пользователь вызывает «mexfunction» где-нибудь из командной строки или сценария m-файла. Фрагмент, заключенный в «**» (когда я пытался выделить его, является проблемой, на которую я смотрю). Из второго взгляда на фрагмент я могу выделить память для указателя dasani в памяти, отличной от памяти Matlab (поскольку есть память с областью действия, ограниченной только функцией mex C ++, и другая область памяти с областью действия, видимой для Программа Matlab). В противном случае, я не уверен, почему Matlab жалуется на эту проблему.

Ответы [ 3 ]

4 голосов
/ 26 мая 2009

MEX API поддерживает как C, так и C ++. Поскольку в C нет никаких методов try / catch или деструкторов, для MEX-функции C нет способа очистить память непосредственно в случае ошибки. Следовательно, MATLAB отслеживает результаты процедур выделения памяти (mxMalloc, mxCalloc, mxRealloc, mxFree и всех функций mxCreate *, которые возвращают mxArrays) во внутреннем списке. Если во время выполнения MEX-функции возникает ошибка (либо путем непосредственного вызова mexErrMsgIdAndTxt, либо с использованием чего-то вроде mexEvalString для вызова кода MATLAB с ошибками), то MATLAB автоматически освободит любую выделенную память на основе mx. Но также, когда MEX-функция завершается нормально, MATLAB будет также освободите любую основанную на mx память, выделенную MEX-функцией. До появления деструкторов это было удобно для авторов MEX, хотя в современном мире C ++ это может сильно раздражать.

Иногда, как в случае с этим вопросом, вы не хотите, чтобы MATLAB автоматически освобождал память. В этом случае вы должны использовать mexMakeMemoryPersistent или mexMakeArrayPersistent для mxArrays.

Вы должны когда-либо передавать указатель на mexMakeMemoryPersistent, только если он был изначально выделен с помощью mxMalloc, mxCalloc или mxRealloc. Итак, этот код

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

плохо с заглавной 'B', если только вы не перегрузили NeedleUSsim :: operator new () для использования mxMalloc, что я бы не рекомендовал. Но если поля dasani выделены с помощью mxMalloc и др., То вы захотите передать их в mexMakeMemoryPersistent. Я бы порекомендовал сделать что-то подобное в конструкторе NeedleUSsim, если это вообще возможно, чтобы он оставался рядом с вызовом mxMalloc.

1 голос
/ 25 мая 2009

Такое ощущение, что mexMakeMemoryPersistent () вызывает все эти проблемы. Я думаю, что вы должны использовать его, чтобы дать команду matlab не удалять память, как только это будет сделано. Но почему Matlab должен удалить указатель дасани? Как этот указатель предоставляется для Matlab и для чего он нужен?

0 голосов
/ 26 мая 2009

Вдобавок к тому, чтобы сделать 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);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...