Примечание
В примерах этого раздела используются функции в перемежающемся комплексном API. Чтобы создать приложения с этими функциями, вызовите mex со специфичной для версии опцией -R2018a.
Когда функция MEX возвращает управление MATLAB ®, она возвращает результаты своих вычислений в выходных аргументах - mxArrays, содержащиеся в аргументах слева plhs[]. Эти массивы должны иметь временную область, поэтому не передавайте массивы, созданные с помощью mexMakeArrayPersistent функция в plhs. MATLAB уничтожает любое mxArray созданной функцией MEX, которая не находится в plhs. MATLAB также освобождает любую память, которая была выделена в функции MEX с помощью mxCalloc, mxMalloc, или mxRealloc функции.
Как правило, MathWorks ® рекомендует, чтобы функции MEX уничтожали их собственные временные массивы и освобождали их динамически выделяемую память. Более эффективно выполнить эту очистку в исходном MEX-файле, чем полагаться на автоматический механизм. Этот подход согласуется с другими приложениями MATLAB API (приложениями MAT-файлов, приложениями ядра и приложениями 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, а затем с помощью mxSetDoubles, MATLAB все еще освободил исходную память. 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, и деструктор освобождают одну и ту же память, что может повредить память.