Примечание
Примеры в этой теме используют функции в чередующемся комплексном API. Чтобы создать приложения с этими функциями, вызовите mex с помощью специфичного для release опции -R2018a.
Когда MEX-функция возвращает управление в MATLAB®, он возвращает результаты своих расчетов в выходных аргументах - mxArrays, содержащиеся в аргументах с левой стороны plhs[]. Эти массивы должны иметь временные возможности, поэтому не передавать массивы, созданные с mexMakeArrayPersistent функция в plhs. MATLAB уничтожает любые mxArray созданный MEX-функцией, которая не находится в plhs. MATLAB также освобождает любую память, которая была выделена в MEX-функция, используя mxCalloc, mxMalloc, или mxRealloc функций.
В целом, MathWorks® рекомендует, чтобы MEX-функции уничтожали свои собственные временные массивы и освобождали свою динамически выделенную память. Более эффективно выполнить эту очистку в исходном файле MEX, чем полагаться на автоматический механизм. Этот подход согласуется с другими приложениями MATLAB API (приложениями MAT-файлов, приложениями engine и MATLAB Compiler™, созданными приложениями, которые не имеют никакого механизма автоматической очистки.)
Однако не уничтожайте mxArray в исходном файле MEX, когда он:
передан в файл MEX в списке справа prhs[]
возвращается в списке слева plhs[]
возвращено mexGetVariablePtr
используется для создания структуры
В этом разделе описываются ситуации, характерные для управления памятью. Мы рекомендуем вам просмотреть код в ваших исходных файлах MEX, чтобы избежать использования этих функций в следующих ситуациях. Для получения дополнительной информации смотрите Автоматическая очистка временных массивов в файлах MEX и постоянных mxArrays. Для руководства по вопросам памяти смотрите Стратегии эффективного использования памяти.
Потенциальные проблемы управления памятью включают:
mxArrayНе используйте mxFree чтобы уничтожить mxArray.
В следующем примере, mxFree не уничтожает объект массива. Эта операция освобождает заголовок структуры, сопоставленный с массивом, но MATLAB все еще работает так, как будто объект массива нужно уничтожить. Таким образом MATLAB пытается уничтожить объект массива, и в процессе снова пытается освободить его заголовок структуры:
mxArray *temp = mxCreateDoubleMatrix(1,1,mxREAL);
...
mxFree(temp); /* INCORRECT */Звонить mxDestroyArray вместо этого:
mxDestroyArray(temp); /* CORRECT */
mxArrayНе звонить mxSetCell или mxSetField варианты с prhs[] как массив представителей.
В следующем примере, когда файл MEX возвращается, MATLAB уничтожает весь массив ячеек. Поскольку это включает в себя представителей камеры, это неявно уничтожает входные параметры файла MEX. Это может привести к нескольким странным результатам, обычно связанным с повреждением рабочей области вызывающего абонента, если используемый правый аргумент является временным массивом (для примера, литералом или результатом выражения):
myfunction('hello')
/* myfunction is the name of your MEX file and your code
/* contains the following: */
mxArray *temp = mxCreateCellMatrix(1,1);
...
mxSetCell(temp, 0, prhs[0]); /* INCORRECT */Сделайте копию аргумента правой стороны с mxDuplicateArray и используйте эту копию в качестве аргумента для mxSetCell (или mxSetField варианты). Для примера:
mxSetCell(temp, 0, mxDuplicateArray(prhs[0])); /* CORRECT */
mxArray с неподходящими даннымиНе звонить mxDestroyArray на mxArray данные которого не были выделены стандартной программой API.
Если вы звоните mxSetDoubles, mxSetComplexDoubles, или любая из типизированных функций доступа к данным, задающих память, которая не была выделена mxCalloc, mxMalloc, или mxRealloc как предполагаемый блок данных (второй аргумент), затем, когда файл MEX возвращается, MATLAB пытается освободить указатели на реальные данные и мнимые данные (если таковые имеются). Таким образом MATLAB пытается освободить память, в этом примере, из программного стека:
mxArray *temp = mxCreateDoubleMatrix(0,0,mxREAL);
double data[5] = {1,2,3,4,5};
...
mxSetM(temp,1); mxSetN(temp,5); mxSetDoubles(temp, data);
/* INCORRECT */Вместо использования mxSetDoubles чтобы задать указатель на данные, создайте mxArray с правильным размером и использованием memcpy чтобы скопировать данные стека в буфер, возвращенный mxGetDoubles:
mxArray *temp = mxCreateDoubleMatrix(1,5,mxREAL);
double data[5] = {1,2,3,4,5};
...
memcpy(mxGetDoubles(temp), data, 5*sizeof(double)); /* CORRECT */До версии 5.2, если вы создали mxArray используя одну из стандартных программ создания API, а затем вы перезаписываете указатель на данные, используя mxSetDoublesMATLAB все еще освободил исходную память. MATLAB больше не освобождает память.
Для примера:
pr = mxCalloc(5*5, sizeof(double)); ... <load data into pr> plhs[0] = mxCreateDoubleMatrix(5,5,mxREAL); mxSetDoubles(plhs[0], pr); /* INCORRECT */
теперь течет 5 * 5 * 8 байтов памяти, где 8 байтов размером с double.
Можно избежать утечки памяти, изменив код на:
plhs[0] = mxCreateDoubleMatrix(5,5,mxREAL); pr = mxGetDoubles(plhs[0]); ... <load data into pr>
или альтернативно:
pr = mxCalloc(5*5, sizeof(double)); ... <load data into pr> plhs[0] = mxCreateDoubleMatrix(5,5,mxREAL); mxFree(mxGetDoubles(plhs[0])); mxSetDoubles(plhs[0], pr);
Первое решение является более эффективным.
Подобные утечки памяти также могут произойти при использовании mxSetDoubles, mxSetComplexDoubles, mxSetIr, mxSetJcили любую из функций доступа к данным с числовым типом. Можно избежать утечек памяти, изменив код, как описано в этом разделе.
Для структуры необходимо вызвать mxDestroyArray только в структуре, а не в массивах полевых данных. Поле в структуре указывает на данные в массиве, используемом mxSetField или mxSetFieldByNumber. Когда mxDestroyArray уничтожает структуру, она пытается пройти вниз через себя и освободить все другие данные, включая память в массивах данных. Если вы звоните mxDestroyArray на каждом массиве данных одна и та же память освобождается дважды, что может привести к повреждению памяти.
В следующем примере создаются три массива: один массив структур aStruct и два массива данных, myDataOne и myDataTwo. Имя поля one содержит указатель на данные в myDataOne, и имя поля two содержит указатель на данные в myDataTwo.
mxArray *myDataOne;
mxArray *myDataTwo;
mxArray *aStruct;
const char *fields[] = { "one", "two" };
myDataOne = mxCreateDoubleScalar(1.0);
myDataTwo = mxCreateDoubleScalar(2.0);
aStruct = mxCreateStructMatrix(1,1,2,fields);
mxSetField( aStruct, 0, "one", myDataOne );
mxSetField( aStruct, 1, "two", myDataTwo );
mxDestroyArray(myDataOne);
mxDestroyArray(myDataTwo);
mxDestroyArray(aStruct); /* tries to free myDataOne and myDataTwo */
Область команды mxDestroyArray(aStruct) уничтожает данные во всех трех массивах:
... aStruct = mxCreateStructMatrix(1,1,2,fields); mxSetField( aStruct, 0, "one", myDataOne ); mxSetField( aStruct, 1, "two", myDataTwo ); mxDestroyArray(aStruct);
Не используйте mxFree или mxDestroyArray функции в деструкторе C++ класса, используемого в MEX-функции. Если MEX-функция выдает ошибку, MATLAB очищает Файл MEX переменные, как описано в Автоматической очистке временных массивов в Файлы MEX.
Если возникает ошибка, из-за которой объект выходит из возможностей, MATLAB вызывает деструктор C++. Освобождение памяти непосредственно в деструкторе означает, что и MATLAB, и деструктор освобождают одну и ту же память, что может испортить память.