Примечание
Примеры в этой теме используют функции в чередующемся комплексном API. Чтобы создать приложения с этими функциями, вызовите mex
с помощью специфичного для release опции -R2018a
.
Когда MEX-функция возвращает управление в MATLAB®, он возвращает результаты своих расчетов в выходных аргументах - mxArray
s, содержащиеся в аргументах с левой стороны 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, а затем вы перезаписываете указатель на данные, используя 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, и деструктор освобождают одну и ту же память, что может испортить память.